forge-openclaw-plugin 0.2.98 → 0.2.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/activity-copy-Bj4h9OcF.js +1 -0
- package/dist/assets/activity-page-5oyCFOns.js +1 -0
- package/dist/assets/ai-surface-workspace-qgk_B57-.js +1 -0
- package/dist/assets/atlas-panel-rfH2qOez.js +1 -0
- package/dist/assets/{board-Ju0h0SeG.js → board-BkDRaMp6.js} +1 -1
- package/dist/assets/calendar-display-preferences-Cid-2RnL.js +1 -0
- package/dist/assets/calendar-page-Bo2iua-a.js +1 -0
- package/dist/assets/calendar-rules-DA1g3QUk.js +1 -0
- package/dist/assets/calendar-ui-Cy1XRwzV.js +1 -0
- package/dist/assets/calendar-week-toolbar-DU1Q4RYj.js +1 -0
- package/dist/assets/charts-P7EVhIog.js +36 -0
- package/dist/assets/companion-sync-lab-page-CosNknOK.js +1 -0
- package/dist/assets/daily-metrics-dashboard-LjuGAB3f.js +1 -0
- package/dist/assets/date-keys-Cj1G3TOn.js +1 -0
- package/dist/assets/entity-links-DwpxhW2H.js +1 -0
- package/dist/assets/entity-note-count-link-BmGDB572.js +1 -0
- package/dist/assets/entity-notes-surface-DgEgicaE.js +1 -0
- package/dist/assets/execution-board-CDRXQB85.js +1 -0
- package/dist/assets/faceted-token-search-CE1YauRd.js +1 -0
- package/dist/assets/flagship-signal-deck-DDds90Gl.js +1 -0
- package/dist/assets/floating-action-menu-CJkI2iFy.js +1 -0
- package/dist/assets/forms-BFlTgZ3W.js +1 -0
- package/dist/assets/goal-detail-page-cJvHaLMQ.js +1 -0
- package/dist/assets/goals-page-f_39hvUV.js +1 -0
- package/dist/assets/graph-BZV40eAE.css +1 -0
- package/dist/assets/graph-D6JLqDbD.js +318 -0
- package/dist/assets/habits-page-DKb96_mj.js +1 -0
- package/dist/assets/health-link-options-Cpx8w7uM.js +1 -0
- package/dist/assets/index-BHTUu_4M.js +19 -0
- package/dist/assets/index-CZbuZQjw.css +1 -0
- package/dist/assets/insight-flow-dialog-pzAzyayN.js +1 -0
- package/dist/assets/insights-page-Dc9oFltJ.js +8 -0
- package/dist/assets/kanban-page-JAxerYh6.js +1 -0
- package/dist/assets/knowledge-graph-page-UQ3skqEi.js +1 -0
- package/dist/assets/life-force-page-BGDbQuVh.js +1 -0
- package/dist/assets/life-force-workspace-B1fYSXRC.js +1 -0
- package/dist/assets/maps-B-YMMjus.css +1 -0
- package/dist/assets/maps-ClgJoCjz.js +803 -0
- package/dist/assets/metric-tile-DX6TclqM.js +1 -0
- package/dist/assets/{motion-DRPJkN3a.js → motion-BeD44FeG.js} +1 -1
- package/dist/assets/movement-page-6HP6nGJx.js +1 -0
- package/dist/assets/note-markdown-DiW2-5d3.js +3 -0
- package/dist/assets/note-tags-input-DDLXf54U.js +1 -0
- package/dist/assets/notes-page-BuguDjhz.js +1 -0
- package/dist/assets/open-in-graph-button-Cg5VrKsC.js +1 -0
- package/dist/assets/orbit-map-GD05-0oS.js +1 -0
- package/dist/assets/overview-page-DuOs2OCB.js +1 -0
- package/dist/assets/page-hero-CQWo1Mm_.js +1 -0
- package/dist/assets/pill-cluster-BJogDRDJ.js +1 -0
- package/dist/assets/preference-entity-handoff-button-D4WAs9pC.js +1 -0
- package/dist/assets/preferences-page-BaJTMU1I.js +1 -0
- package/dist/assets/project-collections-DvaX20q_.js +1 -0
- package/dist/assets/project-detail-page-drPIFZGb.js +1 -0
- package/dist/assets/project-management-hierarchy-page-BUbRXvny.js +1 -0
- package/dist/assets/project-management-section-nav-C2Ud8Zdd.js +1 -0
- package/dist/assets/projects-page-BGzEZUtg.js +1 -0
- package/dist/assets/psyche-behaviors-page-Dmm_Io9D.js +5 -0
- package/dist/assets/psyche-flashcards-page-BgNKJ6QJ.js +1 -0
- package/dist/assets/psyche-goal-map-page-DXJs98Vr.js +1 -0
- package/dist/assets/psyche-graph-CFgs_Bqc.js +1 -0
- package/dist/assets/psyche-metrics-page-zYTJDbyZ.js +1 -0
- package/dist/assets/psyche-mode-guide-page-XPgRfCOf.js +1 -0
- package/dist/assets/psyche-modes-page-B-GA8oRF.js +1 -0
- package/dist/assets/psyche-page--r6a3e1t.js +1 -0
- package/dist/assets/psyche-patterns-page-BM5-3bMm.js +5 -0
- package/dist/assets/psyche-questionnaire-builder-page-CJshQ-mg.js +1 -0
- package/dist/assets/psyche-questionnaire-detail-page-USmR5G5A.js +1 -0
- package/dist/assets/psyche-questionnaire-run-detail-page-D7iBCmTi.js +1 -0
- package/dist/assets/psyche-questionnaire-run-page-Cpil-kDh.js +1 -0
- package/dist/assets/psyche-questionnaires-page-C-_y3VwS.js +1 -0
- package/dist/assets/psyche-report-detail-page--dkSPRaj.js +3 -0
- package/dist/assets/psyche-reports-page-CUaOXmIN.js +1 -0
- package/dist/assets/psyche-schemas-HFmg37Wj.js +1 -0
- package/dist/assets/psyche-schemas-beliefs-page-BX6xaap3.js +9 -0
- package/dist/assets/psyche-screen-time-page-CAAI4mD7.js +1 -0
- package/dist/assets/psyche-self-observation-page-BZ6FLuwa.js +1 -0
- package/dist/assets/psyche-values-page-yEV6MGt8.js +5 -0
- package/dist/assets/query-cache-IQ8W-LNC.js +1 -0
- package/dist/assets/report-chain-fields-fZ8Xd4H6.js +1 -0
- package/dist/assets/rewards-page-C2HQjIAf.js +1 -0
- package/dist/assets/scheduling-rules-editor-BHOpHOrV.js +1 -0
- package/dist/assets/schema-badge-DyKbxb51.js +1 -0
- package/dist/assets/schema-visuals-D6nxjbYC.js +1 -0
- package/dist/assets/select-menu-BX-pZNqL.js +1 -0
- package/dist/assets/settings-agents-page-VuYXTiyc.js +6 -0
- package/dist/assets/settings-bin-page-BNzvYaOk.js +1 -0
- package/dist/assets/settings-calendar-page-CjSFB53S.js +5 -0
- package/dist/assets/settings-data-page-CGSlryuI.js +1 -0
- package/dist/assets/settings-logs-page-BTK5fine.js +1 -0
- package/dist/assets/settings-mobile-page-CRaObOGo.js +1 -0
- package/dist/assets/settings-models-page-DFshpYF8.js +1 -0
- package/dist/assets/settings-page-BP81Mb5R.js +1 -0
- package/dist/assets/settings-rewards-page-CDJ1PH2G.js +1 -0
- package/dist/assets/settings-section-nav-CCFm27r2.js +1 -0
- package/dist/assets/settings-users-page-TdUocFPa.js +1 -0
- package/dist/assets/settings-wiki-page-B2zX0QQG.js +1 -0
- package/dist/assets/sleep-page-cI1GMVzk.js +1 -0
- package/dist/assets/sports-page-06LTqp0V.js +1 -0
- package/dist/assets/state-B-4sS1xO.js +1 -0
- package/dist/assets/strategies-page-DXP9Kx8s.js +1 -0
- package/dist/assets/strategy-detail-page-D6mx_Mik.js +1 -0
- package/dist/assets/strategy-dialog-BvzomTaF.js +1 -0
- package/dist/assets/{table-DewbFlTh.js → table-WfAPUppN.js} +1 -1
- package/dist/assets/task-detail-page-BIWIggdp.js +1 -0
- package/dist/assets/timebox-planning-dialog-CaCnoslG.js +1 -0
- package/dist/assets/today-page-DO2mRPT2.js +1 -0
- package/dist/assets/training-load-page-CyZ0mlEr.js +1 -0
- package/dist/assets/{ui-C2IvSrAz.js → ui-C13Nbgas.js} +4 -4
- package/dist/assets/use-psyche-focus-target-C1C_XjYG.js +1 -0
- package/dist/assets/vendor-CRS-psbw.css +1 -0
- package/dist/assets/vendor-DHkYh85p.js +1052 -0
- package/dist/assets/vitals-page-BQvEjTc6.js +1 -0
- package/dist/assets/weekly-review-page-Tp6Q9CRj.js +1 -0
- package/dist/assets/weight-loss-page-BBzlhLVV.js +1 -0
- package/dist/assets/wiki-article-markdown-DQYohmW2.js +4 -0
- package/dist/assets/wiki-editor-page-Dem_3eZv.js +26 -0
- package/dist/assets/wiki-ingest-history-page-BxoOcCoJ.js +1 -0
- package/dist/assets/wiki-ingest-modal-DhguKk3J.js +1 -0
- package/dist/assets/wiki-page-BLRxVXkl.js +1 -0
- package/dist/assets/workbench-flow-page-DqMkCCTy.js +5 -0
- package/dist/assets/workbench-page-BWd02wPw.js +1 -0
- package/dist/assets/workout-detail-page-BD8u7GyL.js +2 -0
- package/dist/index.html +148 -9
- package/dist/openclaw/tools.js +340 -0
- package/dist/server/server/migrations/065_weight_loss_nutrition_insights.sql +236 -0
- package/dist/server/server/migrations/066_watch_action_receipts.sql +20 -0
- package/dist/server/server/src/app.js +266 -13
- package/dist/server/server/src/health-weight-loss.js +1378 -0
- package/dist/server/server/src/health.js +188 -35
- package/dist/server/server/src/openapi.js +449 -0
- package/dist/server/server/src/services/context.js +6 -7
- package/dist/server/server/src/services/doctor.js +39 -4
- package/dist/server/server/src/services/gamification.js +146 -34
- package/dist/server/server/src/watch-mobile.js +564 -4
- package/dist/server/server/src/web.js +18 -5
- package/dist/server/src/components/ui/info-tooltip.js +48 -3
- package/dist/server/src/lib/api.js +131 -0
- package/dist/server/src/lib/weight-loss-types.js +1 -0
- package/openclaw.plugin.json +14 -1
- package/package.json +1 -1
- package/server/migrations/065_weight_loss_nutrition_insights.sql +236 -0
- package/server/migrations/066_watch_action_receipts.sql +20 -0
- package/skills/forge-openclaw/SKILL.md +26 -5
- package/skills/forge-openclaw/entity_conversation_playbooks.md +134 -5
- package/skills/forge-openclaw/psyche_entity_playbooks.md +45 -0
- package/dist/assets/index-Cn5Wpwau.css +0 -1
- package/dist/assets/index-CwvGs8n4.js +0 -91
- package/dist/assets/vendor-B-Lq_OG3.css +0 -1
- package/dist/assets/vendor-DL2K5ayT.js +0 -2186
|
@@ -1,14 +1,59 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useId, useRef, useState } from "react";
|
|
2
|
+
import { useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
3
4
|
import { CircleHelp } from "lucide-react";
|
|
4
5
|
import { cn } from "../../lib/utils.js";
|
|
6
|
+
const TOOLTIP_GUTTER_PX = 16;
|
|
7
|
+
const TOOLTIP_MAX_WIDTH_PX = 320;
|
|
8
|
+
const TOOLTIP_MIN_HEIGHT_BELOW_PX = 180;
|
|
9
|
+
const TOOLTIP_ESTIMATED_HEIGHT_PX = 220;
|
|
5
10
|
export function FieldHint({ children, className }) {
|
|
6
11
|
return (_jsx("div", { className: cn("text-sm leading-6 text-white/50", className), children: children }));
|
|
7
12
|
}
|
|
8
13
|
export function InfoTooltip({ content, title, label = "Explain this field", className, panelClassName }) {
|
|
9
14
|
const [open, setOpen] = useState(false);
|
|
15
|
+
const [panelStyle, setPanelStyle] = useState({});
|
|
10
16
|
const containerRef = useRef(null);
|
|
17
|
+
const triggerRef = useRef(null);
|
|
11
18
|
const tooltipId = useId();
|
|
19
|
+
const tooltipPanel = typeof document === "undefined"
|
|
20
|
+
? null
|
|
21
|
+
: createPortal(_jsxs("span", { id: tooltipId, role: "tooltip", "aria-hidden": !open, "data-state": open ? "open" : "closed", style: panelStyle, className: cn("pointer-events-none fixed z-[9999] grid overflow-y-auto rounded-[8px] border border-white/10 bg-[#0c111e] px-3 py-2.5 text-left font-sans text-sm normal-case leading-6 tracking-normal text-white/74 shadow-[0_18px_48px_rgba(3,8,18,0.42)] transition", open ? "translate-y-0 opacity-100" : "translate-y-1 opacity-0", panelClassName), children: [title ? (_jsx("span", { className: "text-[11px] font-semibold uppercase tracking-[0.14em] text-white/58", children: title })) : null, _jsx("span", { className: "block min-w-0 whitespace-normal break-words", children: content })] }), document.body);
|
|
22
|
+
useLayoutEffect(() => {
|
|
23
|
+
if (!open) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const positionTooltip = () => {
|
|
27
|
+
const trigger = triggerRef.current;
|
|
28
|
+
if (!trigger) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const rect = trigger.getBoundingClientRect();
|
|
32
|
+
const width = window.innerWidth < 480
|
|
33
|
+
? window.innerWidth - TOOLTIP_GUTTER_PX * 2
|
|
34
|
+
: Math.min(TOOLTIP_MAX_WIDTH_PX, window.innerWidth - TOOLTIP_GUTTER_PX * 2);
|
|
35
|
+
const centeredLeft = rect.left + rect.width / 2 - width / 2;
|
|
36
|
+
const maxLeft = window.innerWidth - width - TOOLTIP_GUTTER_PX;
|
|
37
|
+
const left = Math.max(TOOLTIP_GUTTER_PX, Math.min(centeredLeft, maxLeft));
|
|
38
|
+
const availableBelow = window.innerHeight - rect.bottom;
|
|
39
|
+
const top = availableBelow >= TOOLTIP_MIN_HEIGHT_BELOW_PX
|
|
40
|
+
? rect.bottom + 8
|
|
41
|
+
: Math.max(TOOLTIP_GUTTER_PX, rect.top - TOOLTIP_ESTIMATED_HEIGHT_PX);
|
|
42
|
+
setPanelStyle({
|
|
43
|
+
left,
|
|
44
|
+
maxHeight: `calc(100vh - ${top + TOOLTIP_GUTTER_PX}px)`,
|
|
45
|
+
top,
|
|
46
|
+
width
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
positionTooltip();
|
|
50
|
+
window.addEventListener("resize", positionTooltip);
|
|
51
|
+
window.addEventListener("scroll", positionTooltip, true);
|
|
52
|
+
return () => {
|
|
53
|
+
window.removeEventListener("resize", positionTooltip);
|
|
54
|
+
window.removeEventListener("scroll", positionTooltip, true);
|
|
55
|
+
};
|
|
56
|
+
}, [open]);
|
|
12
57
|
useEffect(() => {
|
|
13
58
|
if (!open) {
|
|
14
59
|
return;
|
|
@@ -21,9 +66,9 @@ export function InfoTooltip({ content, title, label = "Explain this field", clas
|
|
|
21
66
|
document.addEventListener("pointerdown", handlePointerDown);
|
|
22
67
|
return () => document.removeEventListener("pointerdown", handlePointerDown);
|
|
23
68
|
}, [open]);
|
|
24
|
-
return (_jsxs("span", { ref: containerRef, className: cn("relative inline-flex items-center", className), onMouseEnter: () => setOpen(true), onMouseLeave: () => setOpen(false), children: [_jsx("button", { type: "button", "aria-label": label, "aria-describedby": open ? tooltipId : undefined, "aria-expanded": open, className: "inline-flex size-5 items-center justify-center rounded-full text-white/42 transition hover:bg-white/[0.06] hover:text-white/78 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[rgba(192,193,255,0.35)]", onFocus: () => setOpen(true), onBlur: () => setOpen(false), onClick: () => setOpen((current) => !current), onKeyDown: (event) => {
|
|
69
|
+
return (_jsxs("span", { ref: containerRef, className: cn("relative inline-flex items-center", className), onMouseEnter: () => setOpen(true), onMouseLeave: () => setOpen(false), children: [_jsx("button", { ref: triggerRef, type: "button", "aria-label": label, "aria-describedby": open ? tooltipId : undefined, "aria-expanded": open, className: "inline-flex size-5 items-center justify-center rounded-full text-white/42 transition hover:bg-white/[0.06] hover:text-white/78 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[rgba(192,193,255,0.35)]", onFocus: () => setOpen(true), onBlur: () => setOpen(false), onClick: () => setOpen((current) => !current), onKeyDown: (event) => {
|
|
25
70
|
if (event.key === "Escape") {
|
|
26
71
|
setOpen(false);
|
|
27
72
|
}
|
|
28
|
-
}, children: _jsx(CircleHelp, { className: "size-3.5" }) }),
|
|
73
|
+
}, children: _jsx(CircleHelp, { className: "size-3.5" }) }), tooltipPanel] }));
|
|
29
74
|
}
|
|
@@ -1756,6 +1756,137 @@ export function getVitalsView(userIds) {
|
|
|
1756
1756
|
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1757
1757
|
return request(`/api/v1/health/vitals${suffix}`);
|
|
1758
1758
|
}
|
|
1759
|
+
export function getWeightLossView(userIds) {
|
|
1760
|
+
const search = new URLSearchParams();
|
|
1761
|
+
appendUserIds(search, coerceUserIds(userIds));
|
|
1762
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1763
|
+
return request(`/api/v1/health/weight-loss${suffix}`);
|
|
1764
|
+
}
|
|
1765
|
+
export function updateNutritionTarget(patch, userIds) {
|
|
1766
|
+
const search = new URLSearchParams();
|
|
1767
|
+
appendUserIds(search, coerceUserIds(userIds));
|
|
1768
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1769
|
+
return request(`/api/v1/health/weight-loss/target${suffix}`, {
|
|
1770
|
+
method: "PATCH",
|
|
1771
|
+
body: JSON.stringify(patch)
|
|
1772
|
+
});
|
|
1773
|
+
}
|
|
1774
|
+
export function searchNutritionFoods(input) {
|
|
1775
|
+
const search = new URLSearchParams();
|
|
1776
|
+
appendUserIds(search, coerceUserIds(input.userIds));
|
|
1777
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1778
|
+
return request(`/api/v1/health/weight-loss/foods/search${suffix}`, {
|
|
1779
|
+
method: "POST",
|
|
1780
|
+
body: JSON.stringify({ query: input.query, limit: input.limit })
|
|
1781
|
+
});
|
|
1782
|
+
}
|
|
1783
|
+
export function lookupNutritionBarcode(input) {
|
|
1784
|
+
const search = new URLSearchParams();
|
|
1785
|
+
appendUserIds(search, coerceUserIds(input.userIds));
|
|
1786
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1787
|
+
return request(`/api/v1/health/weight-loss/foods/barcode${suffix}`, {
|
|
1788
|
+
method: "POST",
|
|
1789
|
+
body: JSON.stringify({ barcode: input.barcode })
|
|
1790
|
+
});
|
|
1791
|
+
}
|
|
1792
|
+
export function createNutritionFoodLog(input, userIds) {
|
|
1793
|
+
const search = new URLSearchParams();
|
|
1794
|
+
appendUserIds(search, coerceUserIds(userIds));
|
|
1795
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1796
|
+
return request(`/api/v1/health/weight-loss/food-logs${suffix}`, {
|
|
1797
|
+
method: "POST",
|
|
1798
|
+
body: JSON.stringify(input)
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1801
|
+
export function patchNutritionFoodLog(foodLogId, patch, userIds) {
|
|
1802
|
+
const search = new URLSearchParams();
|
|
1803
|
+
appendUserIds(search, coerceUserIds(userIds));
|
|
1804
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1805
|
+
return request(`/api/v1/health/weight-loss/food-logs/${foodLogId}${suffix}`, {
|
|
1806
|
+
method: "PATCH",
|
|
1807
|
+
body: JSON.stringify(patch)
|
|
1808
|
+
});
|
|
1809
|
+
}
|
|
1810
|
+
export function deleteNutritionFoodLog(foodLogId, userIds) {
|
|
1811
|
+
const search = new URLSearchParams();
|
|
1812
|
+
appendUserIds(search, coerceUserIds(userIds));
|
|
1813
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1814
|
+
return request(`/api/v1/health/weight-loss/food-logs/${foodLogId}${suffix}`, { method: "DELETE" });
|
|
1815
|
+
}
|
|
1816
|
+
export function parseNutritionFoodLogWithChatGpt(input) {
|
|
1817
|
+
const search = new URLSearchParams();
|
|
1818
|
+
appendUserIds(search, coerceUserIds(input.userIds));
|
|
1819
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1820
|
+
return request(`/api/v1/health/weight-loss/parse${suffix}`, {
|
|
1821
|
+
method: "POST",
|
|
1822
|
+
body: JSON.stringify({
|
|
1823
|
+
text: input.text,
|
|
1824
|
+
imageDescription: input.imageDescription,
|
|
1825
|
+
loggedAt: input.loggedAt,
|
|
1826
|
+
mealLabel: input.mealLabel
|
|
1827
|
+
})
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1830
|
+
export function createNutritionBodyCheckin(input, userIds) {
|
|
1831
|
+
const search = new URLSearchParams();
|
|
1832
|
+
appendUserIds(search, coerceUserIds(userIds));
|
|
1833
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1834
|
+
return request(`/api/v1/health/weight-loss/body-checkins${suffix}`, {
|
|
1835
|
+
method: "POST",
|
|
1836
|
+
body: JSON.stringify(input)
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1839
|
+
export function createNutritionAppearanceCheckin(input, userIds) {
|
|
1840
|
+
const search = new URLSearchParams();
|
|
1841
|
+
appendUserIds(search, coerceUserIds(userIds));
|
|
1842
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1843
|
+
return request(`/api/v1/health/weight-loss/appearance-checkins${suffix}`, {
|
|
1844
|
+
method: "POST",
|
|
1845
|
+
body: JSON.stringify(input)
|
|
1846
|
+
});
|
|
1847
|
+
}
|
|
1848
|
+
export function createNutritionSubjectiveCheckin(input, userIds) {
|
|
1849
|
+
const search = new URLSearchParams();
|
|
1850
|
+
appendUserIds(search, coerceUserIds(userIds));
|
|
1851
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1852
|
+
return request(`/api/v1/health/weight-loss/subjective-checkins${suffix}`, {
|
|
1853
|
+
method: "POST",
|
|
1854
|
+
body: JSON.stringify(input)
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
export function createNutritionGutCheckin(input, userIds) {
|
|
1858
|
+
const search = new URLSearchParams();
|
|
1859
|
+
appendUserIds(search, coerceUserIds(userIds));
|
|
1860
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1861
|
+
return request(`/api/v1/health/weight-loss/gut-checkins${suffix}`, {
|
|
1862
|
+
method: "POST",
|
|
1863
|
+
body: JSON.stringify(input)
|
|
1864
|
+
});
|
|
1865
|
+
}
|
|
1866
|
+
export function getNutritionPatterns(userIds) {
|
|
1867
|
+
const search = new URLSearchParams();
|
|
1868
|
+
appendUserIds(search, coerceUserIds(userIds));
|
|
1869
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1870
|
+
return request(`/api/v1/health/weight-loss/patterns${suffix}`);
|
|
1871
|
+
}
|
|
1872
|
+
export function createNutritionExperiment(input, userIds) {
|
|
1873
|
+
const search = new URLSearchParams();
|
|
1874
|
+
appendUserIds(search, coerceUserIds(userIds));
|
|
1875
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1876
|
+
return request(`/api/v1/health/weight-loss/experiments${suffix}`, {
|
|
1877
|
+
method: "POST",
|
|
1878
|
+
body: JSON.stringify(input)
|
|
1879
|
+
});
|
|
1880
|
+
}
|
|
1881
|
+
export function patchNutritionExperiment(experimentId, patch, userIds) {
|
|
1882
|
+
const search = new URLSearchParams();
|
|
1883
|
+
appendUserIds(search, coerceUserIds(userIds));
|
|
1884
|
+
const suffix = search.size > 0 ? `?${search.toString()}` : "";
|
|
1885
|
+
return request(`/api/v1/health/weight-loss/experiments/${experimentId}${suffix}`, {
|
|
1886
|
+
method: "PATCH",
|
|
1887
|
+
body: JSON.stringify(patch)
|
|
1888
|
+
});
|
|
1889
|
+
}
|
|
1759
1890
|
export function getMovementDay(input) {
|
|
1760
1891
|
const search = new URLSearchParams();
|
|
1761
1892
|
if (input?.date) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "forge-openclaw-plugin",
|
|
3
3
|
"name": "Forge",
|
|
4
4
|
"description": "Curated OpenClaw adapter for the Forge collaboration API, UI entrypoint, and localhost auto-start runtime.",
|
|
5
|
-
"version": "0.2.
|
|
5
|
+
"version": "0.2.100",
|
|
6
6
|
"activation": {
|
|
7
7
|
"onStartup": true,
|
|
8
8
|
"onCapabilities": [
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
"forge_get_calendar_overview",
|
|
43
43
|
"forge_get_current_work",
|
|
44
44
|
"forge_get_doctor",
|
|
45
|
+
"forge_get_nutrition_patterns",
|
|
45
46
|
"forge_get_operator_context",
|
|
46
47
|
"forge_get_operator_overview",
|
|
47
48
|
"forge_get_preferences_workspace",
|
|
@@ -55,6 +56,7 @@
|
|
|
55
56
|
"forge_get_ui_entrypoint",
|
|
56
57
|
"forge_get_user_directory",
|
|
57
58
|
"forge_get_weekly_review",
|
|
59
|
+
"forge_get_weight_loss_overview",
|
|
58
60
|
"forge_get_wiki_health",
|
|
59
61
|
"forge_get_wiki_page",
|
|
60
62
|
"forge_get_wiki_settings",
|
|
@@ -64,8 +66,15 @@
|
|
|
64
66
|
"forge_ingest_wiki_source",
|
|
65
67
|
"forge_list_questionnaires",
|
|
66
68
|
"forge_list_wiki_pages",
|
|
69
|
+
"forge_log_appearance_checkin",
|
|
70
|
+
"forge_log_body_checkin",
|
|
71
|
+
"forge_log_food",
|
|
72
|
+
"forge_log_gut_checkin",
|
|
73
|
+
"forge_log_subjective_food_effect",
|
|
67
74
|
"forge_log_work",
|
|
75
|
+
"forge_lookup_nutrition_barcode",
|
|
68
76
|
"forge_merge_preferences_contexts",
|
|
77
|
+
"forge_parse_food_log_with_chatgpt",
|
|
69
78
|
"forge_post_insight",
|
|
70
79
|
"forge_publish_questionnaire_draft",
|
|
71
80
|
"forge_recommend_task_timeboxes",
|
|
@@ -73,7 +82,10 @@
|
|
|
73
82
|
"forge_release_task_run",
|
|
74
83
|
"forge_restore_entities",
|
|
75
84
|
"forge_search_entities",
|
|
85
|
+
"forge_search_foods",
|
|
86
|
+
"forge_search_nutrition_foods",
|
|
76
87
|
"forge_search_wiki",
|
|
88
|
+
"forge_start_nutrition_experiment",
|
|
77
89
|
"forge_start_preferences_game",
|
|
78
90
|
"forge_start_questionnaire_run",
|
|
79
91
|
"forge_start_task_run",
|
|
@@ -82,6 +94,7 @@
|
|
|
82
94
|
"forge_sync_calendar_connection",
|
|
83
95
|
"forge_sync_wiki_vault",
|
|
84
96
|
"forge_update_entities",
|
|
97
|
+
"forge_update_nutrition_experiment",
|
|
85
98
|
"forge_update_preferences_score",
|
|
86
99
|
"forge_update_questionnaire_run",
|
|
87
100
|
"forge_update_sleep_session",
|
package/package.json
CHANGED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS nutrition_targets (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
4
|
+
calorie_target REAL,
|
|
5
|
+
protein_grams_target REAL,
|
|
6
|
+
fiber_grams_target REAL,
|
|
7
|
+
carbohydrate_grams_target REAL,
|
|
8
|
+
fat_grams_target REAL,
|
|
9
|
+
weight_goal_kg REAL,
|
|
10
|
+
weekly_rate_goal_kg REAL,
|
|
11
|
+
diet_style TEXT NOT NULL DEFAULT '',
|
|
12
|
+
body_goal TEXT NOT NULL DEFAULT '',
|
|
13
|
+
notes TEXT NOT NULL DEFAULT '',
|
|
14
|
+
created_at TEXT NOT NULL,
|
|
15
|
+
updated_at TEXT NOT NULL
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_nutrition_targets_user
|
|
19
|
+
ON nutrition_targets(user_id);
|
|
20
|
+
|
|
21
|
+
CREATE TABLE IF NOT EXISTS nutrition_food_catalog (
|
|
22
|
+
id TEXT PRIMARY KEY,
|
|
23
|
+
source TEXT NOT NULL,
|
|
24
|
+
source_id TEXT NOT NULL,
|
|
25
|
+
barcode TEXT,
|
|
26
|
+
name TEXT NOT NULL,
|
|
27
|
+
brand TEXT NOT NULL DEFAULT '',
|
|
28
|
+
serving_label TEXT NOT NULL DEFAULT '',
|
|
29
|
+
serving_grams REAL,
|
|
30
|
+
calories REAL,
|
|
31
|
+
protein_grams REAL,
|
|
32
|
+
carbohydrate_grams REAL,
|
|
33
|
+
fat_grams REAL,
|
|
34
|
+
fiber_grams REAL,
|
|
35
|
+
sugar_grams REAL,
|
|
36
|
+
sodium_mg REAL,
|
|
37
|
+
potassium_mg REAL,
|
|
38
|
+
caffeine_mg REAL,
|
|
39
|
+
alcohol_grams REAL,
|
|
40
|
+
nova_group INTEGER,
|
|
41
|
+
nutri_score TEXT,
|
|
42
|
+
tags_json TEXT NOT NULL DEFAULT '[]',
|
|
43
|
+
nutrients_json TEXT NOT NULL DEFAULT '{}',
|
|
44
|
+
confidence REAL NOT NULL DEFAULT 0.65,
|
|
45
|
+
created_at TEXT NOT NULL,
|
|
46
|
+
updated_at TEXT NOT NULL
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_nutrition_food_catalog_source
|
|
50
|
+
ON nutrition_food_catalog(source, source_id);
|
|
51
|
+
|
|
52
|
+
CREATE INDEX IF NOT EXISTS idx_nutrition_food_catalog_barcode
|
|
53
|
+
ON nutrition_food_catalog(barcode);
|
|
54
|
+
|
|
55
|
+
CREATE TABLE IF NOT EXISTS nutrition_food_logs (
|
|
56
|
+
id TEXT PRIMARY KEY,
|
|
57
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
58
|
+
logged_at TEXT NOT NULL,
|
|
59
|
+
meal_label TEXT NOT NULL DEFAULT '',
|
|
60
|
+
source TEXT NOT NULL DEFAULT 'manual',
|
|
61
|
+
confirmation_state TEXT NOT NULL DEFAULT 'confirmed',
|
|
62
|
+
notes TEXT NOT NULL DEFAULT '',
|
|
63
|
+
place_id TEXT,
|
|
64
|
+
stay_id TEXT,
|
|
65
|
+
workout_id TEXT,
|
|
66
|
+
sleep_id TEXT,
|
|
67
|
+
day_key TEXT NOT NULL,
|
|
68
|
+
image_refs_json TEXT NOT NULL DEFAULT '[]',
|
|
69
|
+
parser_provenance_json TEXT NOT NULL DEFAULT '{}',
|
|
70
|
+
links_json TEXT NOT NULL DEFAULT '[]',
|
|
71
|
+
created_at TEXT NOT NULL,
|
|
72
|
+
updated_at TEXT NOT NULL
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
CREATE INDEX IF NOT EXISTS idx_nutrition_food_logs_user_time
|
|
76
|
+
ON nutrition_food_logs(user_id, logged_at DESC);
|
|
77
|
+
|
|
78
|
+
CREATE INDEX IF NOT EXISTS idx_nutrition_food_logs_day
|
|
79
|
+
ON nutrition_food_logs(user_id, day_key);
|
|
80
|
+
|
|
81
|
+
CREATE TABLE IF NOT EXISTS nutrition_meal_items (
|
|
82
|
+
id TEXT PRIMARY KEY,
|
|
83
|
+
log_id TEXT NOT NULL REFERENCES nutrition_food_logs(id) ON DELETE CASCADE,
|
|
84
|
+
food_id TEXT REFERENCES nutrition_food_catalog(id) ON DELETE SET NULL,
|
|
85
|
+
name TEXT NOT NULL,
|
|
86
|
+
quantity REAL NOT NULL DEFAULT 1,
|
|
87
|
+
unit TEXT NOT NULL DEFAULT 'serving',
|
|
88
|
+
grams REAL,
|
|
89
|
+
calories REAL,
|
|
90
|
+
protein_grams REAL,
|
|
91
|
+
carbohydrate_grams REAL,
|
|
92
|
+
fat_grams REAL,
|
|
93
|
+
fiber_grams REAL,
|
|
94
|
+
sugar_grams REAL,
|
|
95
|
+
sodium_mg REAL,
|
|
96
|
+
potassium_mg REAL,
|
|
97
|
+
caffeine_mg REAL,
|
|
98
|
+
alcohol_grams REAL,
|
|
99
|
+
tags_json TEXT NOT NULL DEFAULT '[]',
|
|
100
|
+
nutrients_json TEXT NOT NULL DEFAULT '{}',
|
|
101
|
+
confidence REAL NOT NULL DEFAULT 0.65,
|
|
102
|
+
created_at TEXT NOT NULL,
|
|
103
|
+
updated_at TEXT NOT NULL
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
CREATE INDEX IF NOT EXISTS idx_nutrition_meal_items_log
|
|
107
|
+
ON nutrition_meal_items(log_id);
|
|
108
|
+
|
|
109
|
+
CREATE TABLE IF NOT EXISTS nutrition_body_checkins (
|
|
110
|
+
id TEXT PRIMARY KEY,
|
|
111
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
112
|
+
checked_at TEXT NOT NULL,
|
|
113
|
+
weight_kg REAL,
|
|
114
|
+
waist_cm REAL,
|
|
115
|
+
hip_cm REAL,
|
|
116
|
+
neck_cm REAL,
|
|
117
|
+
chest_cm REAL,
|
|
118
|
+
arm_cm REAL,
|
|
119
|
+
thigh_cm REAL,
|
|
120
|
+
body_fat_percent REAL,
|
|
121
|
+
clothing_fit_score INTEGER,
|
|
122
|
+
notes TEXT NOT NULL DEFAULT '',
|
|
123
|
+
created_at TEXT NOT NULL,
|
|
124
|
+
updated_at TEXT NOT NULL
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
CREATE INDEX IF NOT EXISTS idx_nutrition_body_checkins_user_time
|
|
128
|
+
ON nutrition_body_checkins(user_id, checked_at DESC);
|
|
129
|
+
|
|
130
|
+
CREATE TABLE IF NOT EXISTS nutrition_appearance_checkins (
|
|
131
|
+
id TEXT PRIMARY KEY,
|
|
132
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
133
|
+
checked_at TEXT NOT NULL,
|
|
134
|
+
photo_refs_json TEXT NOT NULL DEFAULT '[]',
|
|
135
|
+
face_puffiness INTEGER,
|
|
136
|
+
leanness INTEGER,
|
|
137
|
+
muscularity INTEGER,
|
|
138
|
+
posture INTEGER,
|
|
139
|
+
bloating_look INTEGER,
|
|
140
|
+
confidence_score INTEGER,
|
|
141
|
+
notes TEXT NOT NULL DEFAULT '',
|
|
142
|
+
created_at TEXT NOT NULL,
|
|
143
|
+
updated_at TEXT NOT NULL
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
CREATE INDEX IF NOT EXISTS idx_nutrition_appearance_checkins_user_time
|
|
147
|
+
ON nutrition_appearance_checkins(user_id, checked_at DESC);
|
|
148
|
+
|
|
149
|
+
CREATE TABLE IF NOT EXISTS nutrition_subjective_checkins (
|
|
150
|
+
id TEXT PRIMARY KEY,
|
|
151
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
152
|
+
checked_at TEXT NOT NULL,
|
|
153
|
+
meal_log_id TEXT REFERENCES nutrition_food_logs(id) ON DELETE SET NULL,
|
|
154
|
+
time_relation TEXT NOT NULL DEFAULT 'unspecified',
|
|
155
|
+
hunger INTEGER,
|
|
156
|
+
fullness INTEGER,
|
|
157
|
+
cravings INTEGER,
|
|
158
|
+
mood INTEGER,
|
|
159
|
+
energy INTEGER,
|
|
160
|
+
focus INTEGER,
|
|
161
|
+
stress INTEGER,
|
|
162
|
+
sleepiness INTEGER,
|
|
163
|
+
crash_score INTEGER,
|
|
164
|
+
notes TEXT NOT NULL DEFAULT '',
|
|
165
|
+
created_at TEXT NOT NULL,
|
|
166
|
+
updated_at TEXT NOT NULL
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
CREATE INDEX IF NOT EXISTS idx_nutrition_subjective_checkins_user_time
|
|
170
|
+
ON nutrition_subjective_checkins(user_id, checked_at DESC);
|
|
171
|
+
|
|
172
|
+
CREATE TABLE IF NOT EXISTS nutrition_gut_checkins (
|
|
173
|
+
id TEXT PRIMARY KEY,
|
|
174
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
175
|
+
checked_at TEXT NOT NULL,
|
|
176
|
+
meal_log_id TEXT REFERENCES nutrition_food_logs(id) ON DELETE SET NULL,
|
|
177
|
+
bristol_stool_type INTEGER,
|
|
178
|
+
stool_frequency INTEGER,
|
|
179
|
+
bloating INTEGER,
|
|
180
|
+
gas INTEGER,
|
|
181
|
+
reflux INTEGER,
|
|
182
|
+
abdominal_pain INTEGER,
|
|
183
|
+
urgency INTEGER,
|
|
184
|
+
nausea INTEGER,
|
|
185
|
+
constipation INTEGER,
|
|
186
|
+
diarrhea INTEGER,
|
|
187
|
+
trigger_tags_json TEXT NOT NULL DEFAULT '[]',
|
|
188
|
+
notes TEXT NOT NULL DEFAULT '',
|
|
189
|
+
created_at TEXT NOT NULL,
|
|
190
|
+
updated_at TEXT NOT NULL
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
CREATE INDEX IF NOT EXISTS idx_nutrition_gut_checkins_user_time
|
|
194
|
+
ON nutrition_gut_checkins(user_id, checked_at DESC);
|
|
195
|
+
|
|
196
|
+
CREATE TABLE IF NOT EXISTS nutrition_hypotheses (
|
|
197
|
+
id TEXT PRIMARY KEY,
|
|
198
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
199
|
+
title TEXT NOT NULL,
|
|
200
|
+
summary TEXT NOT NULL DEFAULT '',
|
|
201
|
+
status TEXT NOT NULL DEFAULT 'candidate',
|
|
202
|
+
confidence REAL NOT NULL DEFAULT 0.25,
|
|
203
|
+
evidence_count INTEGER NOT NULL DEFAULT 0,
|
|
204
|
+
signal_key TEXT NOT NULL DEFAULT '',
|
|
205
|
+
outcome_key TEXT NOT NULL DEFAULT '',
|
|
206
|
+
lag_window TEXT NOT NULL DEFAULT '',
|
|
207
|
+
evidence_json TEXT NOT NULL DEFAULT '{}',
|
|
208
|
+
confounders_json TEXT NOT NULL DEFAULT '[]',
|
|
209
|
+
suggested_action TEXT NOT NULL DEFAULT '',
|
|
210
|
+
created_at TEXT NOT NULL,
|
|
211
|
+
updated_at TEXT NOT NULL
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
CREATE INDEX IF NOT EXISTS idx_nutrition_hypotheses_user_status
|
|
215
|
+
ON nutrition_hypotheses(user_id, status, updated_at DESC);
|
|
216
|
+
|
|
217
|
+
CREATE TABLE IF NOT EXISTS nutrition_experiments (
|
|
218
|
+
id TEXT PRIMARY KEY,
|
|
219
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
220
|
+
hypothesis_id TEXT REFERENCES nutrition_hypotheses(id) ON DELETE SET NULL,
|
|
221
|
+
title TEXT NOT NULL,
|
|
222
|
+
status TEXT NOT NULL DEFAULT 'planned',
|
|
223
|
+
baseline_start TEXT,
|
|
224
|
+
baseline_end TEXT,
|
|
225
|
+
intervention_start TEXT,
|
|
226
|
+
intervention_end TEXT,
|
|
227
|
+
tracked_outcomes_json TEXT NOT NULL DEFAULT '[]',
|
|
228
|
+
protocol_json TEXT NOT NULL DEFAULT '{}',
|
|
229
|
+
adherence_json TEXT NOT NULL DEFAULT '{}',
|
|
230
|
+
result_summary TEXT NOT NULL DEFAULT '',
|
|
231
|
+
created_at TEXT NOT NULL,
|
|
232
|
+
updated_at TEXT NOT NULL
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
CREATE INDEX IF NOT EXISTS idx_nutrition_experiments_user_status
|
|
236
|
+
ON nutrition_experiments(user_id, status, updated_at DESC);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
CREATE TABLE IF NOT EXISTS watch_action_receipts (
|
|
2
|
+
id TEXT PRIMARY KEY,
|
|
3
|
+
pairing_session_id TEXT REFERENCES companion_pairing_sessions(id) ON DELETE SET NULL,
|
|
4
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
5
|
+
action_id TEXT NOT NULL,
|
|
6
|
+
kind TEXT NOT NULL,
|
|
7
|
+
received_at TEXT NOT NULL,
|
|
8
|
+
processed_at TEXT NOT NULL,
|
|
9
|
+
status TEXT NOT NULL,
|
|
10
|
+
result_json TEXT NOT NULL DEFAULT '{}',
|
|
11
|
+
error_json TEXT NOT NULL DEFAULT '{}',
|
|
12
|
+
created_at TEXT NOT NULL,
|
|
13
|
+
UNIQUE (user_id, action_id)
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_watch_action_receipts_user_processed
|
|
17
|
+
ON watch_action_receipts(user_id, processed_at DESC);
|
|
18
|
+
|
|
19
|
+
CREATE INDEX IF NOT EXISTS idx_watch_action_receipts_kind
|
|
20
|
+
ON watch_action_receipts(user_id, kind, processed_at DESC);
|
|
@@ -199,8 +199,17 @@ Wiki navigation and search rule:
|
|
|
199
199
|
Health rule:
|
|
200
200
|
|
|
201
201
|
- Sleep and sports records are first-class health surfaces, not generic notes or tasks.
|
|
202
|
-
- Use `forge_get_sleep_overview`, `forge_get_sports_overview`,
|
|
203
|
-
`forge_get_training_load_overview
|
|
202
|
+
- Use `forge_get_sleep_overview`, `forge_get_sports_overview`,
|
|
203
|
+
`forge_get_training_load_overview`, and `forge_get_weight_loss_overview`
|
|
204
|
+
for health review and trend reading.
|
|
205
|
+
- Use the dedicated nutrition tools for food/body work: `forge_search_foods`, `forge_search_nutrition_foods`,
|
|
206
|
+
`forge_lookup_nutrition_barcode`, `forge_log_food`,
|
|
207
|
+
`forge_parse_food_log_with_chatgpt`, `forge_log_body_checkin`,
|
|
208
|
+
`forge_log_appearance_checkin`, `forge_log_subjective_food_effect`,
|
|
209
|
+
`forge_log_gut_checkin`, `forge_get_nutrition_patterns`,
|
|
210
|
+
`forge_start_nutrition_experiment`, and `forge_update_nutrition_experiment`.
|
|
211
|
+
`forge_parse_food_log_with_chatgpt` must use Forge's configured `openai-codex`
|
|
212
|
+
ChatGPT subscription connection, not a metered OpenAI Platform API path.
|
|
204
213
|
- In `forge_get_agent_onboarding.entityRouteModel.readModelOnlySurfaces`, operator,
|
|
205
214
|
calendar, self-observation, sleep, sports, and training-load read models are published with
|
|
206
215
|
both camelCase names and entity-style aliases where useful, including
|
|
@@ -227,6 +236,14 @@ Entity conversation rule:
|
|
|
227
236
|
- Prefer a progression of:
|
|
228
237
|
concrete example or intent -> working name -> purpose or meaning -> placement in Forge -> operational details -> linked context.
|
|
229
238
|
- Use those same playbooks for action-heavy non-Psyche flows such as `work_adjustment`, `preference_judgment`, `preference_signal`, and specialized `movement`, `life_force`, or `workbench` requests so the conversation starts from what the user is trying to understand, change, add, update, link, or run before you choose the route.
|
|
239
|
+
- When one message combines several jobs, sequence them instead of turning them into
|
|
240
|
+
a broad menu: read before a correction when the current truth is uncertain,
|
|
241
|
+
formulate the primary Psyche record before deriving a flashcard or note, and ask
|
|
242
|
+
only for the missing span, wording, flow, run, node, weekday, or link that changes
|
|
243
|
+
the next action.
|
|
244
|
+
- Before deleting, archiving, invalidating, disconnecting, or replacing a record, confirm
|
|
245
|
+
the exact target and what should remain understandable; for Psyche records, preserve
|
|
246
|
+
therapeutic history unless the user clearly wants removal.
|
|
230
247
|
- When the operation is not already explicit, identify the job first:
|
|
231
248
|
add, update, review, compare, navigate, link, or run. Skip that meta question
|
|
232
249
|
when the action is already obvious from the user's wording.
|
|
@@ -515,7 +532,7 @@ Use these rules when choosing tools.
|
|
|
515
532
|
|
|
516
533
|
Read first with `forge_get_operator_overview`, `forge_get_operator_context`, or `forge_get_current_work` unless the user is clearly asking for one exact known record or one exact write.
|
|
517
534
|
|
|
518
|
-
Before creating or updating an ambiguous stored entity, use `forge_search_entities` to check for duplicates.
|
|
535
|
+
Before creating or updating an ambiguous stored entity, use `forge_search_entities` to check for duplicates. If a likely match 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.
|
|
519
536
|
|
|
520
537
|
Use the batch entity tools for stored records:
|
|
521
538
|
`forge_search_entities`, `forge_create_entities`, `forge_update_entities`, `forge_delete_entities`, `forge_restore_entities`
|
|
@@ -526,8 +543,8 @@ These tools operate on:
|
|
|
526
543
|
Use the wiki tools for SQLite-backed memory work:
|
|
527
544
|
`forge_get_wiki_settings`, `forge_list_wiki_pages`, `forge_get_wiki_page`, `forge_search_wiki`, `forge_upsert_wiki_page`, `forge_get_wiki_health`, `forge_sync_wiki_vault`, `forge_reindex_wiki_embeddings`, `forge_ingest_wiki_source`
|
|
528
545
|
|
|
529
|
-
Use the health tools for review
|
|
530
|
-
`forge_get_sleep_overview`, `forge_get_sports_overview`, `forge_get_training_load_overview`, `forge_update_sleep_session`, `forge_update_workout_session`
|
|
546
|
+
Use the health tools for review, reflective enrichment, and nutrition evidence capture:
|
|
547
|
+
`forge_get_sleep_overview`, `forge_get_sports_overview`, `forge_get_training_load_overview`, `forge_get_weight_loss_overview`, `forge_update_sleep_session`, `forge_update_workout_session`, `forge_search_foods`, `forge_search_nutrition_foods`, `forge_lookup_nutrition_barcode`, `forge_log_food`, `forge_parse_food_log_with_chatgpt`, `forge_log_body_checkin`, `forge_log_appearance_checkin`, `forge_log_subjective_food_effect`, `forge_log_gut_checkin`, `forge_get_nutrition_patterns`, `forge_start_nutrition_experiment`, `forge_update_nutrition_experiment`
|
|
531
548
|
|
|
532
549
|
Use the dedicated domain routes for specialized surfaces that are not simple batch entities:
|
|
533
550
|
|
|
@@ -683,6 +700,10 @@ Use the health tools when the request is about sleep or sports review:
|
|
|
683
700
|
- `forge_get_sleep_overview` to inspect recent nights, averages, regularity, stage breakdown, and linked reflective context
|
|
684
701
|
- `forge_get_sports_overview` to inspect training volume, workout types, effort trends, habit-generated sessions, and linked context
|
|
685
702
|
- `forge_get_training_load_overview` to inspect cardiovascular load, HR zone balance, zone-time buckets, smart training modes, acute/chronic stress, high-intensity pressure, VO2max context, next-workout guidance, and training target fit
|
|
703
|
+
- `forge_get_weight_loss_overview` to inspect calorie balance, protein/fiber targets, body trend, food quality, training fuel, subjective energy, gut comfort, aesthetic look, hypotheses, and experiments
|
|
704
|
+
- `forge_parse_food_log_with_chatgpt` to convert rough meal text or a photo description into a candidate food log through the configured `openai-codex` ChatGPT subscription connection
|
|
705
|
+
- `forge_log_food`, `forge_log_body_checkin`, `forge_log_appearance_checkin`, `forge_log_subjective_food_effect`, and `forge_log_gut_checkin` to preserve the user's food, body-composition, visual-look, energy/craving/performance, and gut-health evidence
|
|
706
|
+
- `forge_get_nutrition_patterns`, `forge_start_nutrition_experiment`, and `forge_update_nutrition_experiment` to turn repeated food/body observations into testable N-of-1 hypotheses
|
|
686
707
|
- `forge_update_sleep_session` to add sleep-quality notes, tags, or links back to Forge entities after review
|
|
687
708
|
- `forge_update_workout_session` to add subjective effort, mood, meaning, tags, or links on one workout after review
|
|
688
709
|
- remember that the UI route is `/sports` while the backend overview route is `/api/v1/health/fitness`; the dedicated training-load UI is `/training-load` and its backend route is `/api/v1/health/training-load`, including zone-time reporting and Combat/Base/Endurance smart modes
|