endurance-coach 0.1.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 (50) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +94 -0
  3. package/bin/claude-coach.js +10 -0
  4. package/dist/cli.d.ts +6 -0
  5. package/dist/cli.js +1077 -0
  6. package/dist/db/client.d.ts +8 -0
  7. package/dist/db/client.js +111 -0
  8. package/dist/db/migrate.d.ts +1 -0
  9. package/dist/db/migrate.js +14 -0
  10. package/dist/db/schema.sql +105 -0
  11. package/dist/index.d.ts +7 -0
  12. package/dist/index.js +13 -0
  13. package/dist/lib/config.d.ts +27 -0
  14. package/dist/lib/config.js +86 -0
  15. package/dist/lib/logging.d.ts +13 -0
  16. package/dist/lib/logging.js +28 -0
  17. package/dist/schema/training-plan.d.ts +288 -0
  18. package/dist/schema/training-plan.js +88 -0
  19. package/dist/schema/training-plan.schema.d.ts +1875 -0
  20. package/dist/schema/training-plan.schema.js +418 -0
  21. package/dist/strava/api.d.ts +5 -0
  22. package/dist/strava/api.js +63 -0
  23. package/dist/strava/oauth.d.ts +4 -0
  24. package/dist/strava/oauth.js +113 -0
  25. package/dist/strava/types.d.ts +46 -0
  26. package/dist/strava/types.js +1 -0
  27. package/dist/viewer/lib/UpdatePlan.d.ts +48 -0
  28. package/dist/viewer/lib/UpdatePlan.js +209 -0
  29. package/dist/viewer/lib/export/erg.d.ts +26 -0
  30. package/dist/viewer/lib/export/erg.js +208 -0
  31. package/dist/viewer/lib/export/fit.d.ts +25 -0
  32. package/dist/viewer/lib/export/fit.js +308 -0
  33. package/dist/viewer/lib/export/ics.d.ts +13 -0
  34. package/dist/viewer/lib/export/ics.js +142 -0
  35. package/dist/viewer/lib/export/index.d.ts +50 -0
  36. package/dist/viewer/lib/export/index.js +229 -0
  37. package/dist/viewer/lib/export/zwo.d.ts +21 -0
  38. package/dist/viewer/lib/export/zwo.js +233 -0
  39. package/dist/viewer/lib/utils.d.ts +14 -0
  40. package/dist/viewer/lib/utils.js +123 -0
  41. package/dist/viewer/main.d.ts +5 -0
  42. package/dist/viewer/main.js +6 -0
  43. package/dist/viewer/stores/changes.d.ts +21 -0
  44. package/dist/viewer/stores/changes.js +49 -0
  45. package/dist/viewer/stores/plan.d.ts +11 -0
  46. package/dist/viewer/stores/plan.js +40 -0
  47. package/dist/viewer/stores/settings.d.ts +53 -0
  48. package/dist/viewer/stores/settings.js +215 -0
  49. package/package.json +74 -0
  50. package/templates/plan-viewer.html +70 -0
@@ -0,0 +1,288 @@
1
+ /**
2
+ * Training Plan JSON Schema
3
+ *
4
+ * Designed to be comprehensive enough for export to:
5
+ * - Zwift (.zwo workouts)
6
+ * - Garmin Connect (.fit workouts)
7
+ * - TrainingPeaks
8
+ * - Other training platforms
9
+ */
10
+ export type Sport = "swim" | "bike" | "run" | "strength" | "brick" | "race" | "rest";
11
+ export type WorkoutType = "rest" | "recovery" | "endurance" | "tempo" | "threshold" | "intervals" | "vo2max" | "sprint" | "race" | "brick" | "technique" | "openwater" | "hills" | "long";
12
+ export type IntensityUnit = "percent_ftp" | "percent_lthr" | "hr_zone" | "pace_zone" | "rpe" | "css_offset";
13
+ export type DurationUnit = "seconds" | "minutes" | "hours" | "meters" | "kilometers" | "miles" | "yards" | "laps";
14
+ export type StepType = "warmup" | "work" | "recovery" | "rest" | "cooldown" | "interval_set";
15
+ export type SwimDistanceUnit = "meters" | "yards";
16
+ export type LandDistanceUnit = "kilometers" | "miles";
17
+ export type FirstDayOfWeek = "monday" | "sunday";
18
+ export interface UnitPreferences {
19
+ swim: SwimDistanceUnit;
20
+ bike: LandDistanceUnit;
21
+ run: LandDistanceUnit;
22
+ firstDayOfWeek: FirstDayOfWeek;
23
+ }
24
+ export declare const defaultPreferences: UnitPreferences;
25
+ export interface IntensityTarget {
26
+ unit: IntensityUnit;
27
+ value: number;
28
+ valueLow?: number;
29
+ valueHigh?: number;
30
+ description?: string;
31
+ }
32
+ export interface DurationTarget {
33
+ unit: DurationUnit;
34
+ value: number;
35
+ }
36
+ export interface WorkoutStep {
37
+ type: StepType;
38
+ name?: string;
39
+ duration: DurationTarget;
40
+ intensity: IntensityTarget;
41
+ cadence?: {
42
+ low: number;
43
+ high: number;
44
+ };
45
+ notes?: string;
46
+ }
47
+ export interface IntervalSet {
48
+ type: "interval_set";
49
+ name?: string;
50
+ repeats: number;
51
+ steps: WorkoutStep[];
52
+ }
53
+ export interface StructuredWorkout {
54
+ warmup?: WorkoutStep[];
55
+ main: (WorkoutStep | IntervalSet)[];
56
+ cooldown?: WorkoutStep[];
57
+ totalDuration?: DurationTarget;
58
+ estimatedTSS?: number;
59
+ estimatedIF?: number;
60
+ }
61
+ export interface Workout {
62
+ id: string;
63
+ sport: Sport;
64
+ type: WorkoutType;
65
+ name: string;
66
+ description: string;
67
+ durationMinutes?: number;
68
+ distanceMeters?: number;
69
+ primaryZone?: string;
70
+ targetHR?: {
71
+ low: number;
72
+ high: number;
73
+ };
74
+ targetPower?: {
75
+ low: number;
76
+ high: number;
77
+ };
78
+ targetPace?: {
79
+ low: string;
80
+ high: string;
81
+ };
82
+ rpe?: number;
83
+ structure?: StructuredWorkout;
84
+ humanReadable?: string;
85
+ completed: boolean;
86
+ completedAt?: string;
87
+ actualDuration?: number;
88
+ actualDistance?: number;
89
+ notes?: string;
90
+ }
91
+ export interface TrainingDay {
92
+ date: string;
93
+ dayOfWeek: string;
94
+ workouts: Workout[];
95
+ }
96
+ export interface WeekSummary {
97
+ totalHours: number;
98
+ totalTSS?: number;
99
+ bySport: {
100
+ [key in Sport]?: {
101
+ sessions: number;
102
+ hours: number;
103
+ km?: number;
104
+ };
105
+ };
106
+ }
107
+ export interface TrainingWeek {
108
+ weekNumber: number;
109
+ startDate: string;
110
+ endDate: string;
111
+ phase: string;
112
+ focus: string;
113
+ targetHours: number;
114
+ days: TrainingDay[];
115
+ summary: WeekSummary;
116
+ isRecoveryWeek: boolean;
117
+ }
118
+ export interface HeartRateZones {
119
+ lthr: number;
120
+ zones: {
121
+ zone: number;
122
+ name: string;
123
+ percentLow: number;
124
+ percentHigh: number;
125
+ hrLow: number;
126
+ hrHigh: number;
127
+ }[];
128
+ }
129
+ export interface PowerZones {
130
+ ftp: number;
131
+ zones: {
132
+ zone: number;
133
+ name: string;
134
+ percentLow: number;
135
+ percentHigh: number;
136
+ wattsLow: number;
137
+ wattsHigh: number;
138
+ }[];
139
+ }
140
+ export interface SwimZones {
141
+ css: string;
142
+ cssSeconds: number;
143
+ zones: {
144
+ zone: number;
145
+ name: string;
146
+ paceOffset: number;
147
+ pace: string;
148
+ }[];
149
+ }
150
+ export interface PaceZones {
151
+ thresholdPace: string;
152
+ thresholdPaceSeconds: number;
153
+ zones: {
154
+ zone: string;
155
+ name: string;
156
+ pace: string;
157
+ paceSeconds: number;
158
+ }[];
159
+ }
160
+ export interface AthleteZones {
161
+ run?: {
162
+ hr?: HeartRateZones;
163
+ pace?: PaceZones;
164
+ };
165
+ bike?: {
166
+ hr?: HeartRateZones;
167
+ power?: PowerZones;
168
+ };
169
+ swim?: SwimZones;
170
+ maxHR?: number;
171
+ restingHR?: number;
172
+ weight?: number;
173
+ }
174
+ export interface AthleteAssessment {
175
+ foundation: {
176
+ raceHistory: string[];
177
+ peakTrainingLoad: number;
178
+ foundationLevel: "beginner" | "intermediate" | "advanced" | "elite";
179
+ yearsInSport: number;
180
+ };
181
+ currentForm: {
182
+ weeklyVolume: {
183
+ total: number;
184
+ swim?: number;
185
+ bike?: number;
186
+ run?: number;
187
+ };
188
+ longestSessions: {
189
+ swim?: number;
190
+ bike?: number;
191
+ run?: number;
192
+ };
193
+ consistency: number;
194
+ timeSincePeakFitness?: string;
195
+ reasonForTimeOff?: string;
196
+ };
197
+ strengths: {
198
+ sport: Sport;
199
+ evidence: string;
200
+ }[];
201
+ limiters: {
202
+ sport: Sport;
203
+ evidence: string;
204
+ }[];
205
+ constraints: string[];
206
+ }
207
+ export interface TrainingPhase {
208
+ name: string;
209
+ startWeek: number;
210
+ endWeek: number;
211
+ focus: string;
212
+ weeklyHoursRange: {
213
+ low: number;
214
+ high: number;
215
+ };
216
+ keyWorkouts: string[];
217
+ physiologicalGoals: string[];
218
+ }
219
+ export interface RaceStrategy {
220
+ event: {
221
+ name: string;
222
+ date: string;
223
+ type: string;
224
+ distances?: {
225
+ swim?: number;
226
+ bike?: number;
227
+ run?: number;
228
+ };
229
+ };
230
+ pacing: {
231
+ swim?: {
232
+ target: string;
233
+ notes: string;
234
+ };
235
+ bike?: {
236
+ targetPower: string;
237
+ targetHR: string;
238
+ notes: string;
239
+ };
240
+ run?: {
241
+ targetPace: string;
242
+ targetHR: string;
243
+ notes: string;
244
+ };
245
+ };
246
+ nutrition: {
247
+ preRace: string;
248
+ during: {
249
+ carbsPerHour: number;
250
+ fluidPerHour: string;
251
+ products: string[];
252
+ };
253
+ notes: string;
254
+ };
255
+ taper: {
256
+ startDate: string;
257
+ volumeReduction: number;
258
+ notes: string;
259
+ };
260
+ raceDay: {
261
+ wakeUpTime?: string;
262
+ preRaceMeal?: string;
263
+ warmUp?: string;
264
+ mentalCues?: string[];
265
+ };
266
+ }
267
+ export interface TrainingPlan {
268
+ version: "1.0";
269
+ meta: {
270
+ id: string;
271
+ athlete: string;
272
+ event: string;
273
+ eventDate: string;
274
+ planStartDate: string;
275
+ planEndDate: string;
276
+ createdAt: string;
277
+ updatedAt: string;
278
+ totalWeeks: number;
279
+ generatedBy: string;
280
+ };
281
+ preferences: UnitPreferences;
282
+ assessment: AthleteAssessment;
283
+ zones: AthleteZones;
284
+ phases: TrainingPhase[];
285
+ weeks: TrainingWeek[];
286
+ raceStrategy: RaceStrategy;
287
+ }
288
+ export declare const exampleWorkout: Workout;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Training Plan JSON Schema
3
+ *
4
+ * Designed to be comprehensive enough for export to:
5
+ * - Zwift (.zwo workouts)
6
+ * - Garmin Connect (.fit workouts)
7
+ * - TrainingPeaks
8
+ * - Other training platforms
9
+ */
10
+ // Default preferences (metric)
11
+ export const defaultPreferences = {
12
+ swim: "meters",
13
+ bike: "kilometers",
14
+ run: "kilometers",
15
+ firstDayOfWeek: "monday",
16
+ };
17
+ // ============================================================================
18
+ // Example/Template
19
+ // ============================================================================
20
+ export const exampleWorkout = {
21
+ id: "week1-tue-swim",
22
+ sport: "swim",
23
+ type: "technique",
24
+ name: "Technique + Endurance",
25
+ description: "Focus on catch and pull mechanics with aerobic base work",
26
+ durationMinutes: 60,
27
+ distanceMeters: 2500,
28
+ primaryZone: "Zone 2",
29
+ targetHR: { low: 120, high: 135 },
30
+ structure: {
31
+ warmup: [
32
+ {
33
+ type: "warmup",
34
+ name: "Easy swim",
35
+ duration: { unit: "meters", value: 300 },
36
+ intensity: { unit: "css_offset", value: 15, description: "CSS + 15s/100m" },
37
+ },
38
+ {
39
+ type: "warmup",
40
+ name: "Drill set",
41
+ duration: { unit: "meters", value: 200 },
42
+ intensity: { unit: "rpe", value: 3, description: "Easy" },
43
+ notes: "4x50m: catch-up, fingertip drag, fist drill, swim",
44
+ },
45
+ ],
46
+ main: [
47
+ {
48
+ type: "interval_set",
49
+ name: "Threshold set",
50
+ repeats: 5,
51
+ steps: [
52
+ {
53
+ type: "work",
54
+ duration: { unit: "meters", value: 100 },
55
+ intensity: { unit: "css_offset", value: 0, description: "CSS pace" },
56
+ },
57
+ {
58
+ type: "rest",
59
+ duration: { unit: "seconds", value: 15 },
60
+ intensity: { unit: "rpe", value: 1 },
61
+ },
62
+ ],
63
+ },
64
+ {
65
+ type: "work",
66
+ name: "Aerobic pull",
67
+ duration: { unit: "meters", value: 800 },
68
+ intensity: { unit: "css_offset", value: 10, description: "CSS + 10s" },
69
+ notes: "With pull buoy, focus on rotation",
70
+ },
71
+ ],
72
+ cooldown: [
73
+ {
74
+ type: "cooldown",
75
+ name: "Easy swim",
76
+ duration: { unit: "meters", value: 200 },
77
+ intensity: { unit: "rpe", value: 2 },
78
+ },
79
+ ],
80
+ totalDuration: { unit: "minutes", value: 60 },
81
+ estimatedTSS: 45,
82
+ },
83
+ humanReadable: `Warm-up: 300m easy, 4x50m drills
84
+ Main: 5x100m @ CSS, 15s rest
85
+ 800m pull @ CSS+10
86
+ Cool-down: 200m easy`,
87
+ completed: false,
88
+ };