trainbud 0.5.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.
Files changed (274) hide show
  1. package/.env.example +11 -0
  2. package/CHANGELOG.md +675 -0
  3. package/LICENSE +21 -0
  4. package/QUICKSTART.md +182 -0
  5. package/README.md +322 -0
  6. package/dist/appDb.d.ts +83 -0
  7. package/dist/appDb.d.ts.map +1 -0
  8. package/dist/appDb.js +239 -0
  9. package/dist/appDb.js.map +1 -0
  10. package/dist/check.d.ts +12 -0
  11. package/dist/check.d.ts.map +1 -0
  12. package/dist/check.js +230 -0
  13. package/dist/check.js.map +1 -0
  14. package/dist/cli.d.ts +3 -0
  15. package/dist/cli.d.ts.map +1 -0
  16. package/dist/cli.js +457 -0
  17. package/dist/cli.js.map +1 -0
  18. package/dist/config.d.ts +61 -0
  19. package/dist/config.d.ts.map +1 -0
  20. package/dist/config.js +241 -0
  21. package/dist/config.js.map +1 -0
  22. package/dist/dashboard.d.ts +8 -0
  23. package/dist/dashboard.d.ts.map +1 -0
  24. package/dist/dashboard.js +1004 -0
  25. package/dist/dashboard.js.map +1 -0
  26. package/dist/dashboardCharts.d.ts +99 -0
  27. package/dist/dashboardCharts.d.ts.map +1 -0
  28. package/dist/dashboardCharts.js +317 -0
  29. package/dist/dashboardCharts.js.map +1 -0
  30. package/dist/dashboardData.d.ts +89 -0
  31. package/dist/dashboardData.d.ts.map +1 -0
  32. package/dist/dashboardData.js +228 -0
  33. package/dist/dashboardData.js.map +1 -0
  34. package/dist/detect/baseline.d.ts +17 -0
  35. package/dist/detect/baseline.d.ts.map +1 -0
  36. package/dist/detect/baseline.js +62 -0
  37. package/dist/detect/baseline.js.map +1 -0
  38. package/dist/detect/countdown.d.ts +30 -0
  39. package/dist/detect/countdown.d.ts.map +1 -0
  40. package/dist/detect/countdown.js +79 -0
  41. package/dist/detect/countdown.js.map +1 -0
  42. package/dist/detect/detectors.d.ts +20 -0
  43. package/dist/detect/detectors.d.ts.map +1 -0
  44. package/dist/detect/detectors.js +291 -0
  45. package/dist/detect/detectors.js.map +1 -0
  46. package/dist/detect/findings.d.ts +29 -0
  47. package/dist/detect/findings.d.ts.map +1 -0
  48. package/dist/detect/findings.js +2 -0
  49. package/dist/detect/findings.js.map +1 -0
  50. package/dist/detect/forecast.d.ts +33 -0
  51. package/dist/detect/forecast.d.ts.map +1 -0
  52. package/dist/detect/forecast.js +122 -0
  53. package/dist/detect/forecast.js.map +1 -0
  54. package/dist/detect/index.d.ts +50 -0
  55. package/dist/detect/index.d.ts.map +1 -0
  56. package/dist/detect/index.js +114 -0
  57. package/dist/detect/index.js.map +1 -0
  58. package/dist/detect/sleepQuality.d.ts +21 -0
  59. package/dist/detect/sleepQuality.d.ts.map +1 -0
  60. package/dist/detect/sleepQuality.js +164 -0
  61. package/dist/detect/sleepQuality.js.map +1 -0
  62. package/dist/detect/trimp.d.ts +22 -0
  63. package/dist/detect/trimp.d.ts.map +1 -0
  64. package/dist/detect/trimp.js +77 -0
  65. package/dist/detect/trimp.js.map +1 -0
  66. package/dist/detect/week.d.ts +31 -0
  67. package/dist/detect/week.d.ts.map +1 -0
  68. package/dist/detect/week.js +184 -0
  69. package/dist/detect/week.js.map +1 -0
  70. package/dist/garmin/auth.d.ts +10 -0
  71. package/dist/garmin/auth.d.ts.map +1 -0
  72. package/dist/garmin/auth.js +81 -0
  73. package/dist/garmin/auth.js.map +1 -0
  74. package/dist/garmin/cache.d.ts +42 -0
  75. package/dist/garmin/cache.d.ts.map +1 -0
  76. package/dist/garmin/cache.js +141 -0
  77. package/dist/garmin/cache.js.map +1 -0
  78. package/dist/garmin/client.d.ts +22 -0
  79. package/dist/garmin/client.d.ts.map +1 -0
  80. package/dist/garmin/client.js +237 -0
  81. package/dist/garmin/client.js.map +1 -0
  82. package/dist/garmin/daily.d.ts +24 -0
  83. package/dist/garmin/daily.d.ts.map +1 -0
  84. package/dist/garmin/daily.js +96 -0
  85. package/dist/garmin/daily.js.map +1 -0
  86. package/dist/garmin/garminApiTypes.d.ts +70 -0
  87. package/dist/garmin/garminApiTypes.d.ts.map +1 -0
  88. package/dist/garmin/garminApiTypes.js +3 -0
  89. package/dist/garmin/garminApiTypes.js.map +1 -0
  90. package/dist/garmin/garminConnect.d.ts +17 -0
  91. package/dist/garmin/garminConnect.d.ts.map +1 -0
  92. package/dist/garmin/garminConnect.js +5 -0
  93. package/dist/garmin/garminConnect.js.map +1 -0
  94. package/dist/garmin/partial.d.ts +32 -0
  95. package/dist/garmin/partial.d.ts.map +1 -0
  96. package/dist/garmin/partial.js +38 -0
  97. package/dist/garmin/partial.js.map +1 -0
  98. package/dist/garmin/rawApi.d.ts +59 -0
  99. package/dist/garmin/rawApi.d.ts.map +1 -0
  100. package/dist/garmin/rawApi.js +113 -0
  101. package/dist/garmin/rawApi.js.map +1 -0
  102. package/dist/garmin/types.d.ts +85 -0
  103. package/dist/garmin/types.d.ts.map +1 -0
  104. package/dist/garmin/types.js +11 -0
  105. package/dist/garmin/types.js.map +1 -0
  106. package/dist/history/capture.d.ts +12 -0
  107. package/dist/history/capture.d.ts.map +1 -0
  108. package/dist/history/capture.js +63 -0
  109. package/dist/history/capture.js.map +1 -0
  110. package/dist/history/context.d.ts +51 -0
  111. package/dist/history/context.d.ts.map +1 -0
  112. package/dist/history/context.js +122 -0
  113. package/dist/history/context.js.map +1 -0
  114. package/dist/history/fallback.d.ts +72 -0
  115. package/dist/history/fallback.d.ts.map +1 -0
  116. package/dist/history/fallback.js +185 -0
  117. package/dist/history/fallback.js.map +1 -0
  118. package/dist/history/ingest.d.ts +44 -0
  119. package/dist/history/ingest.d.ts.map +1 -0
  120. package/dist/history/ingest.js +347 -0
  121. package/dist/history/ingest.js.map +1 -0
  122. package/dist/history/scheduler.d.ts +20 -0
  123. package/dist/history/scheduler.d.ts.map +1 -0
  124. package/dist/history/scheduler.js +54 -0
  125. package/dist/history/scheduler.js.map +1 -0
  126. package/dist/history/schema.d.ts +41 -0
  127. package/dist/history/schema.d.ts.map +1 -0
  128. package/dist/history/schema.js +91 -0
  129. package/dist/history/schema.js.map +1 -0
  130. package/dist/history/store.d.ts +112 -0
  131. package/dist/history/store.d.ts.map +1 -0
  132. package/dist/history/store.js +282 -0
  133. package/dist/history/store.js.map +1 -0
  134. package/dist/httpServer.d.ts +55 -0
  135. package/dist/httpServer.d.ts.map +1 -0
  136. package/dist/httpServer.js +1027 -0
  137. package/dist/httpServer.js.map +1 -0
  138. package/dist/index.d.ts +3 -0
  139. package/dist/index.d.ts.map +1 -0
  140. package/dist/index.js +11 -0
  141. package/dist/index.js.map +1 -0
  142. package/dist/mcpConfig.d.ts +56 -0
  143. package/dist/mcpConfig.d.ts.map +1 -0
  144. package/dist/mcpConfig.js +106 -0
  145. package/dist/mcpConfig.js.map +1 -0
  146. package/dist/pairApi.d.ts +14 -0
  147. package/dist/pairApi.d.ts.map +1 -0
  148. package/dist/pairApi.js +38 -0
  149. package/dist/pairApi.js.map +1 -0
  150. package/dist/paths.d.ts +45 -0
  151. package/dist/paths.d.ts.map +1 -0
  152. package/dist/paths.js +105 -0
  153. package/dist/paths.js.map +1 -0
  154. package/dist/profile.d.ts +123 -0
  155. package/dist/profile.d.ts.map +1 -0
  156. package/dist/profile.js +327 -0
  157. package/dist/profile.js.map +1 -0
  158. package/dist/promptApi.d.ts +43 -0
  159. package/dist/promptApi.d.ts.map +1 -0
  160. package/dist/promptApi.js +328 -0
  161. package/dist/promptApi.js.map +1 -0
  162. package/dist/promptSuggestions.d.ts +16 -0
  163. package/dist/promptSuggestions.d.ts.map +1 -0
  164. package/dist/promptSuggestions.js +141 -0
  165. package/dist/promptSuggestions.js.map +1 -0
  166. package/dist/selfTest.d.ts +53 -0
  167. package/dist/selfTest.d.ts.map +1 -0
  168. package/dist/selfTest.js +225 -0
  169. package/dist/selfTest.js.map +1 -0
  170. package/dist/server.d.ts +10 -0
  171. package/dist/server.d.ts.map +1 -0
  172. package/dist/server.js +67 -0
  173. package/dist/server.js.map +1 -0
  174. package/dist/setup.d.ts +2 -0
  175. package/dist/setup.d.ts.map +1 -0
  176. package/dist/setup.js +210 -0
  177. package/dist/setup.js.map +1 -0
  178. package/dist/toolErrors.d.ts +2 -0
  179. package/dist/toolErrors.d.ts.map +1 -0
  180. package/dist/toolErrors.js +18 -0
  181. package/dist/toolErrors.js.map +1 -0
  182. package/dist/tools/activities.d.ts +18 -0
  183. package/dist/tools/activities.d.ts.map +1 -0
  184. package/dist/tools/activities.js +182 -0
  185. package/dist/tools/activities.js.map +1 -0
  186. package/dist/tools/bodyComposition.d.ts +10 -0
  187. package/dist/tools/bodyComposition.d.ts.map +1 -0
  188. package/dist/tools/bodyComposition.js +139 -0
  189. package/dist/tools/bodyComposition.js.map +1 -0
  190. package/dist/tools/context.d.ts +8 -0
  191. package/dist/tools/context.d.ts.map +1 -0
  192. package/dist/tools/context.js +148 -0
  193. package/dist/tools/context.js.map +1 -0
  194. package/dist/tools/findings.d.ts +7 -0
  195. package/dist/tools/findings.d.ts.map +1 -0
  196. package/dist/tools/findings.js +51 -0
  197. package/dist/tools/findings.js.map +1 -0
  198. package/dist/tools/heartRate.d.ts +10 -0
  199. package/dist/tools/heartRate.d.ts.map +1 -0
  200. package/dist/tools/heartRate.js +105 -0
  201. package/dist/tools/heartRate.js.map +1 -0
  202. package/dist/tools/index.d.ts +66 -0
  203. package/dist/tools/index.d.ts.map +1 -0
  204. package/dist/tools/index.js +101 -0
  205. package/dist/tools/index.js.map +1 -0
  206. package/dist/tools/payloads.d.ts +148 -0
  207. package/dist/tools/payloads.d.ts.map +1 -0
  208. package/dist/tools/payloads.js +2 -0
  209. package/dist/tools/payloads.js.map +1 -0
  210. package/dist/tools/recovery.d.ts +31 -0
  211. package/dist/tools/recovery.d.ts.map +1 -0
  212. package/dist/tools/recovery.js +350 -0
  213. package/dist/tools/recovery.js.map +1 -0
  214. package/dist/tools/sleep.d.ts +10 -0
  215. package/dist/tools/sleep.d.ts.map +1 -0
  216. package/dist/tools/sleep.js +124 -0
  217. package/dist/tools/sleep.js.map +1 -0
  218. package/dist/tools/stress.d.ts +11 -0
  219. package/dist/tools/stress.d.ts.map +1 -0
  220. package/dist/tools/stress.js +108 -0
  221. package/dist/tools/stress.js.map +1 -0
  222. package/dist/tools/trainingInsights.d.ts +15 -0
  223. package/dist/tools/trainingInsights.d.ts.map +1 -0
  224. package/dist/tools/trainingInsights.js +79 -0
  225. package/dist/tools/trainingInsights.js.map +1 -0
  226. package/dist/tools/types.d.ts +12 -0
  227. package/dist/tools/types.d.ts.map +1 -0
  228. package/dist/tools/types.js +2 -0
  229. package/dist/tools/types.js.map +1 -0
  230. package/dist/tools/vo2Max.d.ts +11 -0
  231. package/dist/tools/vo2Max.d.ts.map +1 -0
  232. package/dist/tools/vo2Max.js +110 -0
  233. package/dist/tools/vo2Max.js.map +1 -0
  234. package/dist/tools/week.d.ts +12 -0
  235. package/dist/tools/week.d.ts.map +1 -0
  236. package/dist/tools/week.js +74 -0
  237. package/dist/tools/week.js.map +1 -0
  238. package/dist/usage.d.ts +104 -0
  239. package/dist/usage.d.ts.map +1 -0
  240. package/dist/usage.js +247 -0
  241. package/dist/usage.js.map +1 -0
  242. package/dist/utils/batch.d.ts +2 -0
  243. package/dist/utils/batch.d.ts.map +1 -0
  244. package/dist/utils/batch.js +18 -0
  245. package/dist/utils/batch.js.map +1 -0
  246. package/dist/utils/helpers.d.ts +32 -0
  247. package/dist/utils/helpers.d.ts.map +1 -0
  248. package/dist/utils/helpers.js +188 -0
  249. package/dist/utils/helpers.js.map +1 -0
  250. package/dist/utils/jsonFile.d.ts +19 -0
  251. package/dist/utils/jsonFile.d.ts.map +1 -0
  252. package/dist/utils/jsonFile.js +24 -0
  253. package/dist/utils/jsonFile.js.map +1 -0
  254. package/dist/utils/logger.d.ts +4 -0
  255. package/dist/utils/logger.d.ts.map +1 -0
  256. package/dist/utils/logger.js +97 -0
  257. package/dist/utils/logger.js.map +1 -0
  258. package/dist/utils/secretFile.d.ts +15 -0
  259. package/dist/utils/secretFile.d.ts.map +1 -0
  260. package/dist/utils/secretFile.js +47 -0
  261. package/dist/utils/secretFile.js.map +1 -0
  262. package/dist/utils/stdio.d.ts +10 -0
  263. package/dist/utils/stdio.d.ts.map +1 -0
  264. package/dist/utils/stdio.js +70 -0
  265. package/dist/utils/stdio.js.map +1 -0
  266. package/dist/version.d.ts +2 -0
  267. package/dist/version.d.ts.map +1 -0
  268. package/dist/version.js +7 -0
  269. package/dist/version.js.map +1 -0
  270. package/dist/watchApi.d.ts +264 -0
  271. package/dist/watchApi.d.ts.map +1 -0
  272. package/dist/watchApi.js +333 -0
  273. package/dist/watchApi.js.map +1 -0
  274. package/package.json +77 -0
@@ -0,0 +1,105 @@
1
+ import { appConfig } from "../config.js";
2
+ import { buildToolCacheKey, withCache } from "../garmin/cache.js";
3
+ import { withGarminClient } from "../garmin/client.js";
4
+ import { fetchHeartRateDay, mapHeartRateData } from "../garmin/daily.js";
5
+ import { fetchEachDay } from "../garmin/partial.js";
6
+ import { fetchDaysOrStore, isPartialOrStored, storedFetchNote, } from "../history/fallback.js";
7
+ import { average, calculateTrend, getDateRange } from "../utils/helpers.js";
8
+ // SECTION: Heart Rate Mapping
9
+ async function fetchHeartRateDays(days) {
10
+ const dates = getDateRange(days);
11
+ return fetchDaysOrStore({
12
+ dates,
13
+ source: "heart_rate",
14
+ live: () => withGarminClient(async (client) => fetchEachDay(dates, async (date) => (await fetchHeartRateDay(client, date)).mapped, "heart-rate")),
15
+ fromRaw: (date, payload) => mapHeartRateData(date, payload),
16
+ fromMetrics: (date, metrics) => {
17
+ const restingHeartRate = metrics.get("resting_hr") ?? null;
18
+ const maxHeartRate = metrics.get("max_hr") ?? null;
19
+ if (restingHeartRate === null && maxHeartRate === null) {
20
+ return null;
21
+ }
22
+ // minHeartRate and averageHeartRate are derived from the intraday sample
23
+ // array, which the metric rows never held. Null says "not kept", which is
24
+ // what the renderer already prints as n/a.
25
+ return { date, restingHeartRate, maxHeartRate, minHeartRate: null, averageHeartRate: null };
26
+ },
27
+ dateOf: (day) => day.date,
28
+ });
29
+ }
30
+ // SECTION: Tool Handler
31
+ export function buildHeartRatePayload(days, requestedDays, unreachableDays = 0, stored = {
32
+ storedDays: 0,
33
+ storedThrough: null,
34
+ storedWindowMoved: false,
35
+ }) {
36
+ const restingValues = days
37
+ .map((day) => day.restingHeartRate)
38
+ .filter((value) => value !== null);
39
+ return {
40
+ requestedDays,
41
+ recordedDays: days.length,
42
+ unreachableDays,
43
+ currentResting: restingValues[0] ?? null,
44
+ // A day can be recorded with no resting reading at all. This was
45
+ // Math.round(average([])) before, which printed "Average resting HR: NaN
46
+ // bpm" on any range where nothing measured.
47
+ averageResting: restingValues.length > 0 ? Math.round(average(restingValues)) : null,
48
+ trend: calculateTrend(restingValues, true),
49
+ days,
50
+ storedDays: stored.storedDays,
51
+ storedThrough: stored.storedThrough,
52
+ storedWindowMoved: stored.storedWindowMoved,
53
+ };
54
+ }
55
+ export function renderHeartRateText(payload) {
56
+ const note = storedFetchNote({
57
+ values: payload.days,
58
+ unreachableDays: payload.unreachableDays,
59
+ requestedDays: payload.requestedDays,
60
+ storedDays: payload.storedDays,
61
+ storedThrough: payload.storedThrough,
62
+ storedWindowMoved: payload.storedWindowMoved,
63
+ }, "days");
64
+ if (payload.recordedDays === 0) {
65
+ return note || `No heart rate data found for the last ${payload.requestedDays} days.`;
66
+ }
67
+ const recentLines = payload.days.slice(0, 7).map((day) => {
68
+ return `${day.date}: resting ${day.restingHeartRate ?? "n/a"} bpm, max ${day.maxHeartRate ?? "n/a"} bpm`;
69
+ });
70
+ const lines = [
71
+ `Heart rate trends over ${payload.recordedDays} days:`,
72
+ `Current resting HR: ${payload.currentResting ?? "n/a"} bpm`,
73
+ `Average resting HR: ${payload.averageResting ?? "n/a"} bpm`,
74
+ `Trend: ${payload.trend}`,
75
+ "",
76
+ "Recent days:",
77
+ ...recentLines,
78
+ ];
79
+ return (note ? [note, "", ...lines] : lines).join("\n");
80
+ }
81
+ export async function getHeartRateTrends(input) {
82
+ const days = input.days ?? 30;
83
+ const cacheKey = buildToolCacheKey("get_heart_rate_trends", { days });
84
+ const fetched = await withCache(cacheKey, appConfig.cacheTtlStats, async () => fetchHeartRateDays(days), { isPartial: isPartialOrStored });
85
+ const payload = buildHeartRatePayload(fetched.values, days, fetched.unreachableDays, fetched);
86
+ return {
87
+ type: "text",
88
+ text: renderHeartRateText(payload),
89
+ data: payload,
90
+ };
91
+ }
92
+ export const heartRateToolDefinitions = [
93
+ {
94
+ name: "get_heart_rate_trends",
95
+ description: "Returns resting, max, and average heart rate trends over a time period.",
96
+ inputSchema: {
97
+ days: {
98
+ type: "number",
99
+ description: "Number of days to analyze. Defaults to 30.",
100
+ },
101
+ },
102
+ handler: getHeartRateTrends,
103
+ },
104
+ ];
105
+ //# sourceMappingURL=heartRate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heartRate.js","sourceRoot":"","sources":["../../src/tools/heartRate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { z } from "zod";
2
+ import type { ToolDefinition } from "./types.js";
3
+ import type { ToolResult } 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<ToolResult<unknown>>;
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
+ get_findings: z.ZodObject<{}, z.core.$strip>;
38
+ get_week_review: z.ZodObject<{}, z.core.$strip>;
39
+ remember_context: z.ZodObject<{
40
+ kind: z.ZodEnum<{
41
+ goal: "goal";
42
+ race: "race";
43
+ injury: "injury";
44
+ note: "note";
45
+ }>;
46
+ text: z.ZodString;
47
+ effective_from: z.ZodOptional<z.ZodString>;
48
+ effective_to: z.ZodOptional<z.ZodString>;
49
+ }, z.core.$strip>;
50
+ get_user_context: z.ZodObject<{
51
+ on_date: z.ZodOptional<z.ZodString>;
52
+ include_closed: z.ZodOptional<z.ZodBoolean>;
53
+ }, z.core.$strip>;
54
+ log_subjective: z.ZodObject<{
55
+ kind: z.ZodEnum<{
56
+ rpe: "rpe";
57
+ soreness: "soreness";
58
+ mood: "mood";
59
+ }>;
60
+ value: z.ZodNumber;
61
+ date: z.ZodOptional<z.ZodString>;
62
+ note: z.ZodOptional<z.ZodString>;
63
+ }, z.core.$strip>;
64
+ };
65
+ export declare function listRegisteredToolNames(): string[];
66
+ //# 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;AAYxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAKrD,eAAO,MAAM,YAAY,EAAE,cAAc,EAYxC,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,UAAU,CAAC,OAAO,CAAC,CAAC,CAsB9B;AAED,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDvB,CAAC;AAEF,wBAAgB,uBAAuB,IAAI,MAAM,EAAE,CAElD"}
@@ -0,0 +1,101 @@
1
+ import { z } from "zod";
2
+ import { activityToolDefinitions } from "./activities.js";
3
+ import { contextToolDefinitions } from "./context.js";
4
+ import { findingsToolDefinitions } from "./findings.js";
5
+ import { bodyCompositionToolDefinitions } from "./bodyComposition.js";
6
+ import { heartRateToolDefinitions } from "./heartRate.js";
7
+ import { recoveryToolDefinitions } from "./recovery.js";
8
+ import { sleepToolDefinitions } from "./sleep.js";
9
+ import { stressToolDefinitions } from "./stress.js";
10
+ import { trainingInsightsToolDefinitions } from "./trainingInsights.js";
11
+ import { vo2MaxToolDefinitions } from "./vo2Max.js";
12
+ import { weekToolDefinitions } from "./week.js";
13
+ import { parseIsoDate } from "../utils/helpers.js";
14
+ // SECTION: Tool Registry
15
+ export const toolRegistry = [
16
+ ...activityToolDefinitions,
17
+ ...sleepToolDefinitions,
18
+ ...heartRateToolDefinitions,
19
+ ...recoveryToolDefinitions,
20
+ ...bodyCompositionToolDefinitions,
21
+ ...stressToolDefinitions,
22
+ ...vo2MaxToolDefinitions,
23
+ ...trainingInsightsToolDefinitions,
24
+ ...findingsToolDefinitions,
25
+ ...weekToolDefinitions,
26
+ ...contextToolDefinitions,
27
+ ];
28
+ const toolHandlers = new Map(toolRegistry.map((tool) => [tool.name, tool.handler]));
29
+ export function getToolByName(name) {
30
+ return toolRegistry.find((tool) => tool.name === name);
31
+ }
32
+ export async function executeTool(name, args) {
33
+ const tool = getToolByName(name);
34
+ if (!tool) {
35
+ throw new Error(`Unknown tool: ${name}`);
36
+ }
37
+ const input = args ?? {};
38
+ if (name === "get_activities_range") {
39
+ const startDate = input.start_date;
40
+ const endDate = input.end_date;
41
+ if (typeof startDate !== "string" || typeof endDate !== "string") {
42
+ throw new Error("get_activities_range requires start_date and end_date (ISO 8601 strings).");
43
+ }
44
+ parseIsoDate(startDate);
45
+ parseIsoDate(endDate);
46
+ }
47
+ return tool.handler(input);
48
+ }
49
+ export const toolSchemas = {
50
+ get_latest_activity: z.object({}),
51
+ get_activities_range: z.object({
52
+ start_date: z.string().describe("Start date in ISO 8601 format"),
53
+ end_date: z.string().describe("End date in ISO 8601 format"),
54
+ }),
55
+ get_sleep_data: z.object({
56
+ nights: z.number().int().positive().optional(),
57
+ }),
58
+ get_heart_rate_trends: z.object({
59
+ days: z.number().int().positive().optional(),
60
+ }),
61
+ get_recovery_status: z.object({
62
+ hrv_weight: z.number().positive().optional(),
63
+ sleep_weight: z.number().positive().optional(),
64
+ stress_weight: z.number().positive().optional(),
65
+ resting_hr_weight: z.number().positive().optional(),
66
+ }),
67
+ get_body_composition: z.object({
68
+ days: z.number().int().positive().optional(),
69
+ }),
70
+ get_stress_levels: z.object({
71
+ days: z.number().int().positive().optional(),
72
+ }),
73
+ get_vo2_max_trends: z.object({
74
+ days: z.number().int().positive().optional(),
75
+ }),
76
+ get_training_insights: z.object({
77
+ days: z.number().int().positive().optional(),
78
+ }),
79
+ get_findings: z.object({}),
80
+ get_week_review: z.object({}),
81
+ remember_context: z.object({
82
+ kind: z.enum(["goal", "race", "injury", "note"]).describe("What sort of thing this is"),
83
+ text: z.string().describe("What to remember, in the user's own words where possible"),
84
+ effective_from: z.string().optional().describe("ISO date this became true"),
85
+ effective_to: z.string().optional().describe("ISO date this stops being true"),
86
+ }),
87
+ get_user_context: z.object({
88
+ on_date: z.string().optional().describe("ISO date to evaluate against"),
89
+ include_closed: z.boolean().optional().describe("Include entries that have ended"),
90
+ }),
91
+ log_subjective: z.object({
92
+ kind: z.enum(["rpe", "soreness", "mood"]).describe("Which rating this is"),
93
+ value: z.number().describe("A rating from 1 to 10"),
94
+ date: z.string().optional().describe("ISO date the rating is for"),
95
+ note: z.string().optional().describe("Optional free-text detail"),
96
+ }),
97
+ };
98
+ export function listRegisteredToolNames() {
99
+ return Array.from(toolHandlers.keys());
100
+ }
101
+ //# 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,148 @@
1
+ import type { DailyStressSummary, Vo2MaxEntry } from "../garmin/rawApi.js";
2
+ import type { ContextEntry, SubjectivePoint } from "../history/context.js";
3
+ import type { SubjectiveKind } from "../history/schema.js";
4
+ import type { Finding } from "../detect/findings.js";
5
+ import type { Coverage } from "../detect/index.js";
6
+ import type { ActivitySummary, BodyCompositionEntry, HeartRateDaySummary, RecoveryStatusResult, SleepNightSummary } from "../garmin/types.js";
7
+ /**
8
+ * Where an answer came from.
9
+ *
10
+ * Additive on purpose: the watch parses this JSON on the device and ignores
11
+ * fields it does not know, so a build already on someone's wrist keeps working
12
+ * unchanged. What these let every other reader do is tell a measurement fetched
13
+ * from Connect a moment ago from one read out of TrainBud's own store because
14
+ * Connect would not answer -- two facts that used to render identically, and
15
+ * one of which used to render as "no data" instead.
16
+ */
17
+ export interface StoredProvenance {
18
+ /** Days in this answer that came from the local store, not from Garmin. */
19
+ storedDays: number;
20
+ /** Newest date the stored part covers. Null when nothing came from the store. */
21
+ storedThrough: string | null;
22
+ /**
23
+ * True when the days returned are not the days asked about, because the
24
+ * record stops before the requested window and the window was moved back to
25
+ * where the data is. Every renderer must say so; presenting a fortnight-old
26
+ * week as this week is worse than the empty answer it replaces.
27
+ */
28
+ storedWindowMoved: boolean;
29
+ }
30
+ export interface SleepPayload {
31
+ requestedNights: number;
32
+ recordedNights: number;
33
+ /**
34
+ * Nights whose request FAILED. `recordedNights === 0` with this at zero means
35
+ * the user has no sleep recorded; with this above zero it means Garmin would
36
+ * not answer, and the two must never render the same sentence.
37
+ */
38
+ unreachableNights: number;
39
+ averageScore: number | null;
40
+ nights: SleepNightSummary[];
41
+ /** Nights that came from the local store rather than from Garmin. */
42
+ storedNights: number;
43
+ storedThrough: string | null;
44
+ storedWindowMoved: boolean;
45
+ }
46
+ export interface LatestActivityPayload {
47
+ activity: ActivitySummary | null;
48
+ /** True when Garmin could not be reached and this came out of the store. */
49
+ fromStore: boolean;
50
+ }
51
+ export interface ActivitiesRangePayload {
52
+ startDate: string;
53
+ endDate: string;
54
+ truncated: boolean;
55
+ activities: ActivitySummary[];
56
+ /** True when Garmin could not be reached and these came out of the store. */
57
+ fromStore: boolean;
58
+ }
59
+ export interface HeartRatePayload extends StoredProvenance {
60
+ requestedDays: number;
61
+ recordedDays: number;
62
+ /** Days whose request failed, as opposed to days with nothing measured. */
63
+ unreachableDays: number;
64
+ currentResting: number | null;
65
+ averageResting: number | null;
66
+ trend: string;
67
+ days: HeartRateDaySummary[];
68
+ }
69
+ export interface StressPayload extends StoredProvenance {
70
+ requestedDays: number;
71
+ recordedDays: number;
72
+ /** Days whose request failed, as opposed to days with nothing measured. */
73
+ unreachableDays: number;
74
+ averageStress: number | null;
75
+ trend: string;
76
+ days: DailyStressSummary[];
77
+ }
78
+ export interface Vo2MaxPayload extends StoredProvenance {
79
+ requestedDays: number;
80
+ recordedDays: number;
81
+ /** Days whose request failed, as opposed to days with nothing measured. */
82
+ unreachableDays: number;
83
+ current: number | null;
84
+ oldest: number | null;
85
+ trend: string;
86
+ entries: Vo2MaxEntry[];
87
+ }
88
+ export interface RecoveryPayload {
89
+ date: string;
90
+ recovery: RecoveryStatusResult;
91
+ /**
92
+ * The date the signals behind this score were measured, when they came from
93
+ * the store rather than from a live call. A recovery score is a claim about
94
+ * today; built from a fortnight-old night it is a claim about a fortnight ago,
95
+ * and the difference has to be sayable.
96
+ */
97
+ storedThrough: string | null;
98
+ }
99
+ export interface BodyCompositionPayload extends StoredProvenance {
100
+ requestedDays: number;
101
+ recordedDays: number;
102
+ current: BodyCompositionEntry | null;
103
+ baseline: BodyCompositionEntry | null;
104
+ weightDeltaKg: number | null;
105
+ bodyFatDeltaPercent: number | null;
106
+ weightTrend: string;
107
+ bodyFatTrend: string;
108
+ muscleTrend: string;
109
+ entries: BodyCompositionEntry[];
110
+ }
111
+ export interface TrainingInsightsPayload {
112
+ startDate: string;
113
+ endDate: string;
114
+ latest: ActivitySummary | null;
115
+ activities: ActivitySummary[];
116
+ sleep: SleepPayload | null;
117
+ recovery: RecoveryPayload | null;
118
+ stress: StressPayload | null;
119
+ }
120
+ export interface RememberContextPayload {
121
+ entry: ContextEntry;
122
+ }
123
+ export interface ContextListPayload {
124
+ onDate: string;
125
+ includeClosed: boolean;
126
+ entries: ContextEntry[];
127
+ }
128
+ export interface SubjectivePayload {
129
+ date: string;
130
+ kind: SubjectiveKind;
131
+ value: number;
132
+ note: string | null;
133
+ recent: SubjectivePoint[];
134
+ }
135
+ /**
136
+ * The whole coverage object, not a two-field subset of it.
137
+ *
138
+ * This was typed `{ days, ready }` while the value assigned to it carried
139
+ * `throughDate` and `staleDays` as well. The renderer therefore could not see
140
+ * the two fields that distinguish "not enough history yet" from "plenty, and it
141
+ * stops on 2026-08-21" -- so it printed the cold-start sentence at a 74-day
142
+ * store. A type narrower than its value does not describe data, it hides it.
143
+ */
144
+ export interface FindingsPayload {
145
+ findings: Finding[];
146
+ coverage: Coverage;
147
+ }
148
+ //# sourceMappingURL=payloads.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payloads.d.ts","sourceRoot":"","sources":["../../src/tools/payloads.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=payloads.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payloads.js","sourceRoot":"","sources":["../../src/tools/payloads.ts"],"names":[],"mappings":""}
@@ -0,0 +1,31 @@
1
+ import type { RecoveryStatusResult, RecoveryWeights, ToolResult } from "../garmin/types.js";
2
+ import type { RecoveryPayload } from "./payloads.js";
3
+ import type { ToolDefinition } from "./types.js";
4
+ export declare function normalizeWeights(weights?: Partial<RecoveryWeights>): RecoveryWeights;
5
+ export declare function scoreFromHrv(hrv: number | null, status: string | null): number;
6
+ /**
7
+ * Null when the night was not measured at all.
8
+ *
9
+ * The call site passed `sleep?.sleepTimeSeconds ?? 0`, so a night with no sleep
10
+ * record became zero seconds, fell through every band, and scored 35 out of 100
11
+ * -- a confident bad-night verdict manufactured out of an unworn watch. An hour
12
+ * is the floor for "this is a measurement": nobody's real night is shorter, and
13
+ * Garmin does report tiny durations for naps and for partial wear.
14
+ */
15
+ export declare function scoreFromSleep(score: number | null, durationSeconds: number): number | null;
16
+ export declare function scoreFromStress(stress: number | null): number;
17
+ export declare function scoreFromRestingHr(restingHr: number | null, baseline: number | null): number;
18
+ export declare function buildRecoveryStatus(components: RecoveryStatusResult["components"], weights: RecoveryWeights): RecoveryStatusResult;
19
+ /**
20
+ * The date is passed in rather than read from the clock here, which is what
21
+ * keeps this pure and testable -- the handler below supplies it.
22
+ */
23
+ export declare function renderRecoveryText(payload: RecoveryPayload): string;
24
+ export declare function getRecoveryStatus(input: {
25
+ hrv_weight?: number;
26
+ sleep_weight?: number;
27
+ stress_weight?: number;
28
+ resting_hr_weight?: number;
29
+ }): Promise<ToolResult<RecoveryPayload>>;
30
+ export declare const recoveryToolDefinitions: ToolDefinition[];
31
+ //# sourceMappingURL=recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../../src/tools/recovery.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC5F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAYjD,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,eAAe,CA8BpF;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAqB9E;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,eAAe,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoB3F;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,CAsCtB;AA+GD;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,CAwBnE;AAED,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,UAAU,CAAC,eAAe,CAAC,CAAC,CA+DvC;AAED,eAAO,MAAM,uBAAuB,EAAE,cAAc,EAyBnD,CAAC"}