garmin-bud 0.2.0
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/.env.example +11 -0
- package/CHANGELOG.md +56 -0
- package/LICENSE +21 -0
- package/QUICKSTART.md +174 -0
- package/README.md +227 -0
- package/dist/appDb.d.ts +32 -0
- package/dist/appDb.d.ts.map +1 -0
- package/dist/appDb.js +131 -0
- package/dist/appDb.js.map +1 -0
- package/dist/check.d.ts +9 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +156 -0
- package/dist/check.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +187 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +108 -0
- package/dist/config.js.map +1 -0
- package/dist/dashboard.d.ts +4 -0
- package/dist/dashboard.d.ts.map +1 -0
- package/dist/dashboard.js +111 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/garmin/auth.d.ts +10 -0
- package/dist/garmin/auth.d.ts.map +1 -0
- package/dist/garmin/auth.js +81 -0
- package/dist/garmin/auth.js.map +1 -0
- package/dist/garmin/cache.d.ts +20 -0
- package/dist/garmin/cache.d.ts.map +1 -0
- package/dist/garmin/cache.js +115 -0
- package/dist/garmin/cache.js.map +1 -0
- package/dist/garmin/client.d.ts +5 -0
- package/dist/garmin/client.d.ts.map +1 -0
- package/dist/garmin/client.js +68 -0
- package/dist/garmin/client.js.map +1 -0
- package/dist/garmin/garminApiTypes.d.ts +70 -0
- package/dist/garmin/garminApiTypes.d.ts.map +1 -0
- package/dist/garmin/garminApiTypes.js +3 -0
- package/dist/garmin/garminApiTypes.js.map +1 -0
- package/dist/garmin/garminConnect.d.ts +17 -0
- package/dist/garmin/garminConnect.d.ts.map +1 -0
- package/dist/garmin/garminConnect.js +5 -0
- package/dist/garmin/garminConnect.js.map +1 -0
- package/dist/garmin/rawApi.d.ts +18 -0
- package/dist/garmin/rawApi.d.ts.map +1 -0
- package/dist/garmin/rawApi.js +53 -0
- package/dist/garmin/rawApi.js.map +1 -0
- package/dist/garmin/types.d.ts +68 -0
- package/dist/garmin/types.d.ts.map +1 -0
- package/dist/garmin/types.js +11 -0
- package/dist/garmin/types.js.map +1 -0
- package/dist/httpServer.d.ts +7 -0
- package/dist/httpServer.d.ts.map +1 -0
- package/dist/httpServer.js +386 -0
- package/dist/httpServer.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/mcpConfig.d.ts +37 -0
- package/dist/mcpConfig.d.ts.map +1 -0
- package/dist/mcpConfig.js +83 -0
- package/dist/mcpConfig.js.map +1 -0
- package/dist/pairApi.d.ts +14 -0
- package/dist/pairApi.d.ts.map +1 -0
- package/dist/pairApi.js +34 -0
- package/dist/pairApi.js.map +1 -0
- package/dist/promptApi.d.ts +13 -0
- package/dist/promptApi.d.ts.map +1 -0
- package/dist/promptApi.js +102 -0
- package/dist/promptApi.js.map +1 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +67 -0
- package/dist/server.js.map +1 -0
- package/dist/setup.d.ts +2 -0
- package/dist/setup.d.ts.map +1 -0
- package/dist/setup.js +194 -0
- package/dist/setup.js.map +1 -0
- package/dist/toolErrors.d.ts +2 -0
- package/dist/toolErrors.d.ts.map +1 -0
- package/dist/toolErrors.js +18 -0
- package/dist/toolErrors.js.map +1 -0
- package/dist/tools/activities.d.ts +11 -0
- package/dist/tools/activities.d.ts.map +1 -0
- package/dist/tools/activities.js +134 -0
- package/dist/tools/activities.js.map +1 -0
- package/dist/tools/bodyComposition.d.ts +7 -0
- package/dist/tools/bodyComposition.d.ts.map +1 -0
- package/dist/tools/bodyComposition.js +97 -0
- package/dist/tools/bodyComposition.js.map +1 -0
- package/dist/tools/heartRate.d.ts +7 -0
- package/dist/tools/heartRate.d.ts.map +1 -0
- package/dist/tools/heartRate.js +88 -0
- package/dist/tools/heartRate.js.map +1 -0
- package/dist/tools/index.d.ts +39 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +77 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/recovery.d.ts +16 -0
- package/dist/tools/recovery.d.ts.map +1 -0
- package/dist/tools/recovery.js +214 -0
- package/dist/tools/recovery.js.map +1 -0
- package/dist/tools/sleep.d.ts +7 -0
- package/dist/tools/sleep.d.ts.map +1 -0
- package/dist/tools/sleep.js +93 -0
- package/dist/tools/sleep.js.map +1 -0
- package/dist/tools/stress.d.ts +7 -0
- package/dist/tools/stress.d.ts.map +1 -0
- package/dist/tools/stress.js +69 -0
- package/dist/tools/stress.js.map +1 -0
- package/dist/tools/trainingInsights.d.ts +7 -0
- package/dist/tools/trainingInsights.d.ts.map +1 -0
- package/dist/tools/trainingInsights.js +61 -0
- package/dist/tools/trainingInsights.js.map +1 -0
- package/dist/tools/types.d.ts +12 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/vo2Max.d.ts +7 -0
- package/dist/tools/vo2Max.d.ts.map +1 -0
- package/dist/tools/vo2Max.js +72 -0
- package/dist/tools/vo2Max.js.map +1 -0
- package/dist/utils/batch.d.ts +2 -0
- package/dist/utils/batch.d.ts.map +1 -0
- package/dist/utils/batch.js +18 -0
- package/dist/utils/batch.js.map +1 -0
- package/dist/utils/helpers.d.ts +19 -0
- package/dist/utils/helpers.d.ts.map +1 -0
- package/dist/utils/helpers.js +131 -0
- package/dist/utils/helpers.js.map +1 -0
- package/dist/utils/logger.d.ts +4 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +59 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/dist/watchApi.d.ts +47 -0
- package/dist/watchApi.d.ts.map +1 -0
- package/dist/watchApi.js +222 -0
- package/dist/watchApi.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { appConfig } from "../config.js";
|
|
2
|
+
import { buildToolCacheKey, withCache } from "../garmin/cache.js";
|
|
3
|
+
import { withGarminClient } from "../garmin/client.js";
|
|
4
|
+
import { mapInBatches } from "../utils/batch.js";
|
|
5
|
+
import { calculateTrend, formatIsoDate, getDateRange, } from "../utils/helpers.js";
|
|
6
|
+
// SECTION: Body Composition Mapping
|
|
7
|
+
async function fetchBodyComposition(days) {
|
|
8
|
+
const dates = getDateRange(days);
|
|
9
|
+
const entries = await withGarminClient(async (client) => {
|
|
10
|
+
const batches = await mapInBatches(dates, async (date) => {
|
|
11
|
+
const weightData = await client.getDailyWeightData(date);
|
|
12
|
+
return weightData.dateWeightList.map((entry) => ({
|
|
13
|
+
date: entry.calendarDate || formatIsoDate(date),
|
|
14
|
+
weightKg: entry.weight ?? null,
|
|
15
|
+
bodyFatPercent: entry.bodyFat ?? null,
|
|
16
|
+
muscleMassKg: entry.muscleMass ?? null,
|
|
17
|
+
bmi: entry.bmi ?? null,
|
|
18
|
+
}));
|
|
19
|
+
});
|
|
20
|
+
return batches.flat();
|
|
21
|
+
});
|
|
22
|
+
const uniqueByDate = new Map();
|
|
23
|
+
for (const entry of entries) {
|
|
24
|
+
uniqueByDate.set(entry.date, entry);
|
|
25
|
+
}
|
|
26
|
+
return Array.from(uniqueByDate.values()).sort((left, right) => right.date.localeCompare(left.date));
|
|
27
|
+
}
|
|
28
|
+
// SECTION: Tool Handler
|
|
29
|
+
export async function getBodyComposition(input) {
|
|
30
|
+
const days = input.days ?? 30;
|
|
31
|
+
const cacheKey = buildToolCacheKey("get_body_composition", { days });
|
|
32
|
+
const entries = await withCache(cacheKey, appConfig.cacheTtlStats, async () => {
|
|
33
|
+
return fetchBodyComposition(days);
|
|
34
|
+
});
|
|
35
|
+
if (entries.length === 0) {
|
|
36
|
+
return {
|
|
37
|
+
type: "text",
|
|
38
|
+
text: `No body composition data found for the last ${days} days.`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const current = entries[0];
|
|
42
|
+
const baseline = entries[entries.length - 1];
|
|
43
|
+
const weightTrend = calculateTrend(entries.map((entry) => entry.weightKg).filter((value) => value !== null), true);
|
|
44
|
+
const bodyFatTrend = calculateTrend(entries
|
|
45
|
+
.map((entry) => entry.bodyFatPercent)
|
|
46
|
+
.filter((value) => value !== null), true);
|
|
47
|
+
const muscleTrend = calculateTrend(entries
|
|
48
|
+
.map((entry) => entry.muscleMassKg)
|
|
49
|
+
.filter((value) => value !== null), false);
|
|
50
|
+
const weightDelta = current?.weightKg !== null &&
|
|
51
|
+
current?.weightKg !== undefined &&
|
|
52
|
+
baseline?.weightKg !== null &&
|
|
53
|
+
baseline?.weightKg !== undefined
|
|
54
|
+
? current.weightKg - baseline.weightKg
|
|
55
|
+
: null;
|
|
56
|
+
const bodyFatDelta = current?.bodyFatPercent !== null &&
|
|
57
|
+
current?.bodyFatPercent !== undefined &&
|
|
58
|
+
baseline?.bodyFatPercent !== null &&
|
|
59
|
+
baseline?.bodyFatPercent !== undefined
|
|
60
|
+
? current.bodyFatPercent - baseline.bodyFatPercent
|
|
61
|
+
: null;
|
|
62
|
+
const lines = entries.slice(0, 10).map((entry) => {
|
|
63
|
+
return `${entry.date}: ${entry.weightKg?.toFixed(1) ?? "n/a"} kg | body fat ${entry.bodyFatPercent?.toFixed(1) ?? "n/a"}% | muscle ${entry.muscleMassKg?.toFixed(1) ?? "n/a"} kg`;
|
|
64
|
+
});
|
|
65
|
+
const text = [
|
|
66
|
+
`Body composition over ${entries.length} recorded days:`,
|
|
67
|
+
`Current weight: ${current?.weightKg?.toFixed(1) ?? "n/a"} kg`,
|
|
68
|
+
`Current body fat: ${current?.bodyFatPercent?.toFixed(1) ?? "n/a"}%`,
|
|
69
|
+
`Current muscle mass: ${current?.muscleMassKg?.toFixed(1) ?? "n/a"} kg`,
|
|
70
|
+
`Weight change from baseline: ${weightDelta !== null ? `${weightDelta.toFixed(1)} kg` : "n/a"}`,
|
|
71
|
+
`Body fat change from baseline: ${bodyFatDelta !== null ? `${bodyFatDelta.toFixed(1)}%` : "n/a"}`,
|
|
72
|
+
`Weight trend: ${weightTrend}`,
|
|
73
|
+
`Body fat trend: ${bodyFatTrend}`,
|
|
74
|
+
`Muscle trend: ${muscleTrend}`,
|
|
75
|
+
"",
|
|
76
|
+
"Recent entries:",
|
|
77
|
+
...lines,
|
|
78
|
+
].join("\n");
|
|
79
|
+
return {
|
|
80
|
+
type: "text",
|
|
81
|
+
text,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
export const bodyCompositionToolDefinitions = [
|
|
85
|
+
{
|
|
86
|
+
name: "get_body_composition",
|
|
87
|
+
description: "Returns weight, body fat, and muscle mass trends over a time period.",
|
|
88
|
+
inputSchema: {
|
|
89
|
+
days: {
|
|
90
|
+
type: "number",
|
|
91
|
+
description: "Number of days to analyze. Defaults to 30.",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
handler: getBodyComposition,
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
//# sourceMappingURL=bodyComposition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bodyComposition.js","sourceRoot":"","sources":["../../src/tools/bodyComposition.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ToolTextResult } from "../garmin/types.js";
|
|
2
|
+
import type { ToolDefinition } from "./types.js";
|
|
3
|
+
export declare function getHeartRateTrends(input: {
|
|
4
|
+
days?: number;
|
|
5
|
+
}): Promise<ToolTextResult>;
|
|
6
|
+
export declare const heartRateToolDefinitions: ToolDefinition[];
|
|
7
|
+
//# sourceMappingURL=heartRate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heartRate.d.ts","sourceRoot":"","sources":["../../src/tools/heartRate.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAuB,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC9E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAkDjD,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAyC1F;AAED,eAAO,MAAM,wBAAwB,EAAE,cAAc,EAYpD,CAAC"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { appConfig } from "../config.js";
|
|
2
|
+
import { buildToolCacheKey, withCache } from "../garmin/cache.js";
|
|
3
|
+
import { withGarminClient } from "../garmin/client.js";
|
|
4
|
+
import { mapInBatches } from "../utils/batch.js";
|
|
5
|
+
import { average, calculateTrend, formatIsoDate, getDateRange, } from "../utils/helpers.js";
|
|
6
|
+
// SECTION: Heart Rate Mapping
|
|
7
|
+
async function fetchHeartRateDays(days) {
|
|
8
|
+
const dates = getDateRange(days);
|
|
9
|
+
return withGarminClient(async (client) => {
|
|
10
|
+
const summaries = await mapInBatches(dates, async (date) => {
|
|
11
|
+
try {
|
|
12
|
+
const heartRate = await client.getHeartRate(date);
|
|
13
|
+
if (!heartRate) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const samples = (heartRate.heartRateValues ?? [])
|
|
17
|
+
.flat()
|
|
18
|
+
.filter((entry) => entry != null)
|
|
19
|
+
.map((entry) => entry.heartrate);
|
|
20
|
+
const averageHeartRate = samples.length > 0 ? average(samples) : null;
|
|
21
|
+
if (heartRate.restingHeartRate == null && averageHeartRate == null) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
date: formatIsoDate(date),
|
|
26
|
+
restingHeartRate: heartRate.restingHeartRate ?? null,
|
|
27
|
+
maxHeartRate: heartRate.maxHeartRate ?? null,
|
|
28
|
+
minHeartRate: heartRate.minHeartRate ?? null,
|
|
29
|
+
averageHeartRate,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return summaries.filter((summary) => summary !== null);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// SECTION: Tool Handler
|
|
40
|
+
export async function getHeartRateTrends(input) {
|
|
41
|
+
const days = input.days ?? 30;
|
|
42
|
+
const cacheKey = buildToolCacheKey("get_heart_rate_trends", { days });
|
|
43
|
+
const summaries = await withCache(cacheKey, appConfig.cacheTtlStats, async () => {
|
|
44
|
+
return fetchHeartRateDays(days);
|
|
45
|
+
});
|
|
46
|
+
if (summaries.length === 0) {
|
|
47
|
+
return {
|
|
48
|
+
type: "text",
|
|
49
|
+
text: `No heart rate data found for the last ${days} days.`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const restingValues = summaries
|
|
53
|
+
.map((summary) => summary.restingHeartRate)
|
|
54
|
+
.filter((value) => value !== null);
|
|
55
|
+
const trend = calculateTrend(restingValues, true);
|
|
56
|
+
const currentResting = restingValues[0] ?? null;
|
|
57
|
+
const baselineResting = average(restingValues);
|
|
58
|
+
const recentLines = summaries.slice(0, 7).map((summary) => {
|
|
59
|
+
return `${summary.date}: resting ${summary.restingHeartRate ?? "n/a"} bpm, max ${summary.maxHeartRate ?? "n/a"} bpm`;
|
|
60
|
+
});
|
|
61
|
+
const text = [
|
|
62
|
+
`Heart rate trends over ${summaries.length} days:`,
|
|
63
|
+
`Current resting HR: ${currentResting ?? "n/a"} bpm`,
|
|
64
|
+
`Average resting HR: ${Math.round(baselineResting)} bpm`,
|
|
65
|
+
`Trend: ${trend}`,
|
|
66
|
+
"",
|
|
67
|
+
"Recent days:",
|
|
68
|
+
...recentLines,
|
|
69
|
+
].join("\n");
|
|
70
|
+
return {
|
|
71
|
+
type: "text",
|
|
72
|
+
text,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
export const heartRateToolDefinitions = [
|
|
76
|
+
{
|
|
77
|
+
name: "get_heart_rate_trends",
|
|
78
|
+
description: "Returns resting, max, and average heart rate trends over a time period.",
|
|
79
|
+
inputSchema: {
|
|
80
|
+
days: {
|
|
81
|
+
type: "number",
|
|
82
|
+
description: "Number of days to analyze. Defaults to 30.",
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
handler: getHeartRateTrends,
|
|
86
|
+
},
|
|
87
|
+
];
|
|
88
|
+
//# sourceMappingURL=heartRate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heartRate.js","sourceRoot":"","sources":["../../src/tools/heartRate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EACL,OAAO,EACP,cAAc,EACd,aAAa,EACb,YAAY,GACb,MAAM,qBAAqB,CAAC;AAE7B,8BAA8B;AAE9B,KAAK,UAAU,kBAAkB,CAAC,IAAY;IAC5C,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAEjC,OAAO,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QACvC,MAAM,SAAS,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACzD,IAAI,CAAC;gBACH,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;gBAClD,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,MAAM,OAAO,GAAG,CAAC,SAAS,CAAC,eAAe,IAAI,EAAE,CAAC;qBAC9C,IAAI,EAAE;qBACN,MAAM,CAAC,CAAC,KAAK,EAAkC,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC;qBAChE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBACnC,MAAM,gBAAgB,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBAEtE,IAAI,SAAS,CAAC,gBAAgB,IAAI,IAAI,IAAI,gBAAgB,IAAI,IAAI,EAAE,CAAC;oBACnE,OAAO,IAAI,CAAC;gBACd,CAAC;gBAED,OAAO;oBACL,IAAI,EAAE,aAAa,CAAC,IAAI,CAAC;oBACzB,gBAAgB,EAAE,SAAS,CAAC,gBAAgB,IAAI,IAAI;oBACpD,YAAY,EAAE,SAAS,CAAC,YAAY,IAAI,IAAI;oBAC5C,YAAY,EAAE,SAAS,CAAC,YAAY,IAAI,IAAI;oBAC5C,gBAAgB;iBACjB,CAAC;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,EAAkC,EAAE,CAAC,OAAO,KAAK,IAAI,CAAC,CAAC;IACzF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,wBAAwB;AAExB,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAAwB;IAC/D,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;IAC9B,MAAM,QAAQ,GAAG,iBAAiB,CAAC,uBAAuB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IAEtE,MAAM,SAAS,GAAG,MAAM,SAAS,CAAC,QAAQ,EAAE,SAAS,CAAC,aAAa,EAAE,KAAK,IAAI,EAAE;QAC9E,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,yCAAyC,IAAI,QAAQ;SAC5D,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,SAAS;SAC5B,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC;SAC1C,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;IAEtD,MAAM,KAAK,GAAG,cAAc,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;IAClD,MAAM,cAAc,GAAG,aAAa,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IAChD,MAAM,eAAe,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAE/C,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QACxD,OAAO,GAAG,OAAO,CAAC,IAAI,aAAa,OAAO,CAAC,gBAAgB,IAAI,KAAK,aAAa,OAAO,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC;IACvH,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG;QACX,0BAA0B,SAAS,CAAC,MAAM,QAAQ;QAClD,uBAAuB,cAAc,IAAI,KAAK,MAAM;QACpD,uBAAuB,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM;QACxD,UAAU,KAAK,EAAE;QACjB,EAAE;QACF,cAAc;QACd,GAAG,WAAW;KACf,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,IAAI;KACL,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,wBAAwB,GAAqB;IACxD;QACE,IAAI,EAAE,uBAAuB;QAC7B,WAAW,EAAE,yEAAyE;QACtF,WAAW,EAAE;YACX,IAAI,EAAE;gBACJ,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,4CAA4C;aAC1D;SACF;QACD,OAAO,EAAE,kBAAkB;KAC5B;CACF,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ToolDefinition } from "./types.js";
|
|
3
|
+
import type { ToolTextResult } from "../garmin/types.js";
|
|
4
|
+
export declare const toolRegistry: ToolDefinition[];
|
|
5
|
+
export declare function getToolByName(name: string): ToolDefinition | undefined;
|
|
6
|
+
export declare function executeTool(name: string, args: Record<string, unknown> | undefined): Promise<ToolTextResult>;
|
|
7
|
+
export declare const toolSchemas: {
|
|
8
|
+
get_latest_activity: z.ZodObject<{}, z.core.$strip>;
|
|
9
|
+
get_activities_range: z.ZodObject<{
|
|
10
|
+
start_date: z.ZodString;
|
|
11
|
+
end_date: z.ZodString;
|
|
12
|
+
}, z.core.$strip>;
|
|
13
|
+
get_sleep_data: z.ZodObject<{
|
|
14
|
+
nights: z.ZodOptional<z.ZodNumber>;
|
|
15
|
+
}, z.core.$strip>;
|
|
16
|
+
get_heart_rate_trends: z.ZodObject<{
|
|
17
|
+
days: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
}, z.core.$strip>;
|
|
19
|
+
get_recovery_status: z.ZodObject<{
|
|
20
|
+
hrv_weight: z.ZodOptional<z.ZodNumber>;
|
|
21
|
+
sleep_weight: z.ZodOptional<z.ZodNumber>;
|
|
22
|
+
stress_weight: z.ZodOptional<z.ZodNumber>;
|
|
23
|
+
resting_hr_weight: z.ZodOptional<z.ZodNumber>;
|
|
24
|
+
}, z.core.$strip>;
|
|
25
|
+
get_body_composition: z.ZodObject<{
|
|
26
|
+
days: z.ZodOptional<z.ZodNumber>;
|
|
27
|
+
}, z.core.$strip>;
|
|
28
|
+
get_stress_levels: z.ZodObject<{
|
|
29
|
+
days: z.ZodOptional<z.ZodNumber>;
|
|
30
|
+
}, z.core.$strip>;
|
|
31
|
+
get_vo2_max_trends: z.ZodObject<{
|
|
32
|
+
days: z.ZodOptional<z.ZodNumber>;
|
|
33
|
+
}, z.core.$strip>;
|
|
34
|
+
get_training_insights: z.ZodObject<{
|
|
35
|
+
days: z.ZodOptional<z.ZodNumber>;
|
|
36
|
+
}, z.core.$strip>;
|
|
37
|
+
};
|
|
38
|
+
export declare function listRegisteredToolNames(): string[];
|
|
39
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAKzD,eAAO,MAAM,YAAY,EAAE,cAAc,EASxC,CAAC;AAMF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAEtE;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GACxC,OAAO,CAAC,cAAc,CAAC,CAsBzB;AAED,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BvB,CAAC;AAEF,wBAAgB,uBAAuB,IAAI,MAAM,EAAE,CAElD"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { activityToolDefinitions } from "./activities.js";
|
|
3
|
+
import { bodyCompositionToolDefinitions } from "./bodyComposition.js";
|
|
4
|
+
import { heartRateToolDefinitions } from "./heartRate.js";
|
|
5
|
+
import { recoveryToolDefinitions } from "./recovery.js";
|
|
6
|
+
import { sleepToolDefinitions } from "./sleep.js";
|
|
7
|
+
import { stressToolDefinitions } from "./stress.js";
|
|
8
|
+
import { trainingInsightsToolDefinitions } from "./trainingInsights.js";
|
|
9
|
+
import { vo2MaxToolDefinitions } from "./vo2Max.js";
|
|
10
|
+
import { parseIsoDate } from "../utils/helpers.js";
|
|
11
|
+
// SECTION: Tool Registry
|
|
12
|
+
export const toolRegistry = [
|
|
13
|
+
...activityToolDefinitions,
|
|
14
|
+
...sleepToolDefinitions,
|
|
15
|
+
...heartRateToolDefinitions,
|
|
16
|
+
...recoveryToolDefinitions,
|
|
17
|
+
...bodyCompositionToolDefinitions,
|
|
18
|
+
...stressToolDefinitions,
|
|
19
|
+
...vo2MaxToolDefinitions,
|
|
20
|
+
...trainingInsightsToolDefinitions,
|
|
21
|
+
];
|
|
22
|
+
const toolHandlers = new Map(toolRegistry.map((tool) => [tool.name, tool.handler]));
|
|
23
|
+
export function getToolByName(name) {
|
|
24
|
+
return toolRegistry.find((tool) => tool.name === name);
|
|
25
|
+
}
|
|
26
|
+
export async function executeTool(name, args) {
|
|
27
|
+
const tool = getToolByName(name);
|
|
28
|
+
if (!tool) {
|
|
29
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
30
|
+
}
|
|
31
|
+
const input = args ?? {};
|
|
32
|
+
if (name === "get_activities_range") {
|
|
33
|
+
const startDate = input.start_date;
|
|
34
|
+
const endDate = input.end_date;
|
|
35
|
+
if (typeof startDate !== "string" || typeof endDate !== "string") {
|
|
36
|
+
throw new Error("get_activities_range requires start_date and end_date (ISO 8601 strings).");
|
|
37
|
+
}
|
|
38
|
+
parseIsoDate(startDate);
|
|
39
|
+
parseIsoDate(endDate);
|
|
40
|
+
}
|
|
41
|
+
return tool.handler(input);
|
|
42
|
+
}
|
|
43
|
+
export const toolSchemas = {
|
|
44
|
+
get_latest_activity: z.object({}),
|
|
45
|
+
get_activities_range: z.object({
|
|
46
|
+
start_date: z.string().describe("Start date in ISO 8601 format"),
|
|
47
|
+
end_date: z.string().describe("End date in ISO 8601 format"),
|
|
48
|
+
}),
|
|
49
|
+
get_sleep_data: z.object({
|
|
50
|
+
nights: z.number().int().positive().optional(),
|
|
51
|
+
}),
|
|
52
|
+
get_heart_rate_trends: z.object({
|
|
53
|
+
days: z.number().int().positive().optional(),
|
|
54
|
+
}),
|
|
55
|
+
get_recovery_status: z.object({
|
|
56
|
+
hrv_weight: z.number().positive().optional(),
|
|
57
|
+
sleep_weight: z.number().positive().optional(),
|
|
58
|
+
stress_weight: z.number().positive().optional(),
|
|
59
|
+
resting_hr_weight: z.number().positive().optional(),
|
|
60
|
+
}),
|
|
61
|
+
get_body_composition: z.object({
|
|
62
|
+
days: z.number().int().positive().optional(),
|
|
63
|
+
}),
|
|
64
|
+
get_stress_levels: z.object({
|
|
65
|
+
days: z.number().int().positive().optional(),
|
|
66
|
+
}),
|
|
67
|
+
get_vo2_max_trends: z.object({
|
|
68
|
+
days: z.number().int().positive().optional(),
|
|
69
|
+
}),
|
|
70
|
+
get_training_insights: z.object({
|
|
71
|
+
days: z.number().int().positive().optional(),
|
|
72
|
+
}),
|
|
73
|
+
};
|
|
74
|
+
export function listRegisteredToolNames() {
|
|
75
|
+
return Array.from(toolHandlers.keys());
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { RecoveryStatusResult, RecoveryWeights, ToolTextResult } from "../garmin/types.js";
|
|
2
|
+
import type { ToolDefinition } from "./types.js";
|
|
3
|
+
export declare function normalizeWeights(weights?: Partial<RecoveryWeights>): RecoveryWeights;
|
|
4
|
+
export declare function scoreFromHrv(hrv: number | null, status: string | null): number;
|
|
5
|
+
export declare function scoreFromSleep(score: number | null, durationSeconds: number): number;
|
|
6
|
+
export declare function scoreFromStress(stress: number | null): number;
|
|
7
|
+
export declare function scoreFromRestingHr(restingHr: number | null, baseline: number | null): number;
|
|
8
|
+
export declare function buildRecoveryStatus(components: RecoveryStatusResult["components"], weights: RecoveryWeights): RecoveryStatusResult;
|
|
9
|
+
export declare function getRecoveryStatus(input: {
|
|
10
|
+
hrv_weight?: number;
|
|
11
|
+
sleep_weight?: number;
|
|
12
|
+
stress_weight?: number;
|
|
13
|
+
resting_hr_weight?: number;
|
|
14
|
+
}): Promise<ToolTextResult>;
|
|
15
|
+
export declare const recoveryToolDefinitions: ToolDefinition[];
|
|
16
|
+
//# sourceMappingURL=recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../../src/tools/recovery.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAChG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAYjD,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CAcpF;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAqB9E;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,CAgBpF;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAe7D;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CA6B5F;AAED,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,oBAAoB,CAAC,YAAY,CAAC,EAC9C,OAAO,EAAE,eAAe,GACvB,oBAAoB,CAyBtB;AAiCD,wBAAsB,iBAAiB,CAAC,KAAK,EAAE;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,OAAO,CAAC,cAAc,CAAC,CAuD1B;AAED,eAAO,MAAM,uBAAuB,EAAE,cAAc,EAyBnD,CAAC"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { appConfig } from "../config.js";
|
|
2
|
+
import { buildToolCacheKey, withCache } from "../garmin/cache.js";
|
|
3
|
+
import { withGarminClient } from "../garmin/client.js";
|
|
4
|
+
import { clamp, formatIsoDate, getDateRange, getYesterday } from "../utils/helpers.js";
|
|
5
|
+
// SECTION: Recovery Scoring
|
|
6
|
+
const DEFAULT_WEIGHTS = {
|
|
7
|
+
hrv: 0.3,
|
|
8
|
+
sleep: 0.3,
|
|
9
|
+
stress: 0.2,
|
|
10
|
+
restingHr: 0.2,
|
|
11
|
+
};
|
|
12
|
+
export function normalizeWeights(weights) {
|
|
13
|
+
const merged = { ...DEFAULT_WEIGHTS, ...weights };
|
|
14
|
+
const total = merged.hrv + merged.sleep + merged.stress + merged.restingHr;
|
|
15
|
+
if (total <= 0) {
|
|
16
|
+
return DEFAULT_WEIGHTS;
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
hrv: merged.hrv / total,
|
|
20
|
+
sleep: merged.sleep / total,
|
|
21
|
+
stress: merged.stress / total,
|
|
22
|
+
restingHr: merged.restingHr / total,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export function scoreFromHrv(hrv, status) {
|
|
26
|
+
if (hrv === null) {
|
|
27
|
+
if (status === "BALANCED") {
|
|
28
|
+
return 80;
|
|
29
|
+
}
|
|
30
|
+
if (status === "LOW") {
|
|
31
|
+
return 45;
|
|
32
|
+
}
|
|
33
|
+
return 60;
|
|
34
|
+
}
|
|
35
|
+
if (hrv >= 60) {
|
|
36
|
+
return 95;
|
|
37
|
+
}
|
|
38
|
+
if (hrv >= 45) {
|
|
39
|
+
return 80;
|
|
40
|
+
}
|
|
41
|
+
if (hrv >= 30) {
|
|
42
|
+
return 60;
|
|
43
|
+
}
|
|
44
|
+
return 40;
|
|
45
|
+
}
|
|
46
|
+
export function scoreFromSleep(score, durationSeconds) {
|
|
47
|
+
if (score !== null) {
|
|
48
|
+
return clamp(score, 0, 100);
|
|
49
|
+
}
|
|
50
|
+
const hours = durationSeconds / 3600;
|
|
51
|
+
if (hours >= 8) {
|
|
52
|
+
return 90;
|
|
53
|
+
}
|
|
54
|
+
if (hours >= 7) {
|
|
55
|
+
return 75;
|
|
56
|
+
}
|
|
57
|
+
if (hours >= 6) {
|
|
58
|
+
return 55;
|
|
59
|
+
}
|
|
60
|
+
return 35;
|
|
61
|
+
}
|
|
62
|
+
export function scoreFromStress(stress) {
|
|
63
|
+
if (stress === null) {
|
|
64
|
+
return 60;
|
|
65
|
+
}
|
|
66
|
+
if (stress <= 15) {
|
|
67
|
+
return 95;
|
|
68
|
+
}
|
|
69
|
+
if (stress <= 25) {
|
|
70
|
+
return 75;
|
|
71
|
+
}
|
|
72
|
+
if (stress <= 35) {
|
|
73
|
+
return 55;
|
|
74
|
+
}
|
|
75
|
+
return 35;
|
|
76
|
+
}
|
|
77
|
+
export function scoreFromRestingHr(restingHr, baseline) {
|
|
78
|
+
if (restingHr === null) {
|
|
79
|
+
return 60;
|
|
80
|
+
}
|
|
81
|
+
if (baseline === null) {
|
|
82
|
+
if (restingHr <= 50) {
|
|
83
|
+
return 90;
|
|
84
|
+
}
|
|
85
|
+
if (restingHr <= 60) {
|
|
86
|
+
return 80;
|
|
87
|
+
}
|
|
88
|
+
if (restingHr <= 70) {
|
|
89
|
+
return 65;
|
|
90
|
+
}
|
|
91
|
+
return 45;
|
|
92
|
+
}
|
|
93
|
+
const delta = restingHr - baseline;
|
|
94
|
+
if (delta <= -2) {
|
|
95
|
+
return 90;
|
|
96
|
+
}
|
|
97
|
+
if (delta <= 2) {
|
|
98
|
+
return 75;
|
|
99
|
+
}
|
|
100
|
+
if (delta <= 5) {
|
|
101
|
+
return 55;
|
|
102
|
+
}
|
|
103
|
+
return 35;
|
|
104
|
+
}
|
|
105
|
+
export function buildRecoveryStatus(components, weights) {
|
|
106
|
+
const score = Math.round(components.hrvScore * weights.hrv +
|
|
107
|
+
components.sleepScore * weights.sleep +
|
|
108
|
+
components.stressScore * weights.stress +
|
|
109
|
+
components.restingHrScore * weights.restingHr);
|
|
110
|
+
let status = "good";
|
|
111
|
+
let recommendation = "Moderate training is reasonable. Listen to your body during hard efforts.";
|
|
112
|
+
if (score >= 80) {
|
|
113
|
+
status = "recovered";
|
|
114
|
+
recommendation = "You look recovered. Hard training or a quality session is appropriate today.";
|
|
115
|
+
}
|
|
116
|
+
else if (score < 60) {
|
|
117
|
+
status = "fatigued";
|
|
118
|
+
recommendation = "Recovery looks limited. Favor easy training, mobility, or a rest day.";
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
score,
|
|
122
|
+
status,
|
|
123
|
+
recommendation,
|
|
124
|
+
components,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
async function fetchRecoverySignals() {
|
|
128
|
+
const today = new Date();
|
|
129
|
+
const candidates = [getYesterday(), ...getDateRange(3).slice(1)];
|
|
130
|
+
return withGarminClient(async (client) => {
|
|
131
|
+
let sleepData = { dailySleepDTO: undefined };
|
|
132
|
+
for (const date of candidates) {
|
|
133
|
+
const candidate = await client.getSleepData(date);
|
|
134
|
+
if (candidate.dailySleepDTO) {
|
|
135
|
+
sleepData = candidate;
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const heartRate = await client.getHeartRate(today);
|
|
140
|
+
return {
|
|
141
|
+
sleepData,
|
|
142
|
+
restingHeartRate: heartRate.restingHeartRate ?? null,
|
|
143
|
+
baselineRestingHeartRate: heartRate.lastSevenDaysAvgRestingHeartRate ?? null,
|
|
144
|
+
};
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
// SECTION: Tool Handler
|
|
148
|
+
export async function getRecoveryStatus(input) {
|
|
149
|
+
const weights = normalizeWeights({
|
|
150
|
+
hrv: input.hrv_weight,
|
|
151
|
+
sleep: input.sleep_weight,
|
|
152
|
+
stress: input.stress_weight,
|
|
153
|
+
restingHr: input.resting_hr_weight,
|
|
154
|
+
});
|
|
155
|
+
const cacheKey = buildToolCacheKey("get_recovery_status", {
|
|
156
|
+
hrv: weights.hrv,
|
|
157
|
+
sleep: weights.sleep,
|
|
158
|
+
stress: weights.stress,
|
|
159
|
+
restingHr: weights.restingHr,
|
|
160
|
+
});
|
|
161
|
+
const recovery = await withCache(cacheKey, appConfig.cacheTtlStats, async () => {
|
|
162
|
+
const signals = await fetchRecoverySignals();
|
|
163
|
+
const sleep = signals.sleepData.dailySleepDTO;
|
|
164
|
+
const components = {
|
|
165
|
+
hrvScore: scoreFromHrv(signals.sleepData.avgOvernightHrv ?? null, signals.sleepData.hrvStatus ?? null),
|
|
166
|
+
sleepScore: scoreFromSleep(sleep?.sleepScores?.overall?.value ?? null, sleep?.sleepTimeSeconds ?? 0),
|
|
167
|
+
stressScore: scoreFromStress(sleep?.avgSleepStress ?? null),
|
|
168
|
+
restingHrScore: scoreFromRestingHr(signals.restingHeartRate, signals.baselineRestingHeartRate),
|
|
169
|
+
};
|
|
170
|
+
return buildRecoveryStatus(components, weights);
|
|
171
|
+
});
|
|
172
|
+
const text = [
|
|
173
|
+
`Recovery score: ${recovery.score}/100 (${recovery.status})`,
|
|
174
|
+
recovery.recommendation,
|
|
175
|
+
"",
|
|
176
|
+
"Component scores:",
|
|
177
|
+
`- HRV: ${recovery.components.hrvScore}`,
|
|
178
|
+
`- Sleep: ${recovery.components.sleepScore}`,
|
|
179
|
+
`- Stress: ${recovery.components.stressScore}`,
|
|
180
|
+
`- Resting HR: ${recovery.components.restingHrScore}`,
|
|
181
|
+
"",
|
|
182
|
+
`Date: ${formatIsoDate(new Date())}`,
|
|
183
|
+
].join("\n");
|
|
184
|
+
return {
|
|
185
|
+
type: "text",
|
|
186
|
+
text,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
export const recoveryToolDefinitions = [
|
|
190
|
+
{
|
|
191
|
+
name: "get_recovery_status",
|
|
192
|
+
description: "Combines HRV, sleep, stress, and resting heart rate into a recovery score and training recommendation.",
|
|
193
|
+
inputSchema: {
|
|
194
|
+
hrv_weight: {
|
|
195
|
+
type: "number",
|
|
196
|
+
description: "Optional weight for HRV in the recovery score.",
|
|
197
|
+
},
|
|
198
|
+
sleep_weight: {
|
|
199
|
+
type: "number",
|
|
200
|
+
description: "Optional weight for sleep in the recovery score.",
|
|
201
|
+
},
|
|
202
|
+
stress_weight: {
|
|
203
|
+
type: "number",
|
|
204
|
+
description: "Optional weight for stress in the recovery score.",
|
|
205
|
+
},
|
|
206
|
+
resting_hr_weight: {
|
|
207
|
+
type: "number",
|
|
208
|
+
description: "Optional weight for resting heart rate in the recovery score.",
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
handler: getRecoveryStatus,
|
|
212
|
+
},
|
|
213
|
+
];
|
|
214
|
+
//# sourceMappingURL=recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.js","sourceRoot":"","sources":["../../src/tools/recovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ToolTextResult } from "../garmin/types.js";
|
|
2
|
+
import type { ToolDefinition } from "./types.js";
|
|
3
|
+
export declare function getSleepDataTool(input: {
|
|
4
|
+
nights?: number;
|
|
5
|
+
}): Promise<ToolTextResult>;
|
|
6
|
+
export declare const sleepToolDefinitions: ToolDefinition[];
|
|
7
|
+
//# sourceMappingURL=sleep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/tools/sleep.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAqB,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA4DjD,wBAAsB,gBAAgB,CAAC,KAAK,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAsC1F;AAED,eAAO,MAAM,oBAAoB,EAAE,cAAc,EAYhD,CAAC"}
|