@workingdevshero/olympia-ait-adapter 1.0.0 → 1.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.
@@ -1,13 +1,15 @@
1
- import { EXERCISE_NAME_COL, NOTES_COL, WEEK_REPS_COLS, WEEK_WEIGHT_COLS, } from "./layout.js";
1
+ import { EXERCISE_NAME_COL } from "./layout.js";
2
2
  import { exerciseNameStyle, groupLabelStyle, NOTES_CELL, weekRepsCellStyle, weekWeightCellStyle, } from "./styles.js";
3
3
  /**
4
4
  * Stamps one exercise block onto the worksheet starting at `startRow`.
5
5
  *
6
6
  * Layout rules (N = exercise.sets.length):
7
- * - With groupLabel: name occupies the first N−1 rows of col C (merged
8
- * when N > 2); group label sits in col C of the last row.
9
- * - Without groupLabel: name occupies all N rows of col C (merged when
10
- * N > 1); no group-label row.
7
+ * - With a label: name occupies the first N−1 rows of col C (merged
8
+ * when N > 2); the label sits in col C of the last row.
9
+ * - With a label and a single set: the set sits on the name row and the
10
+ * label gets a row of its own below it, with empty prescription cells.
11
+ * - Without a label: name occupies all N rows of col C (merged when
12
+ * N > 1); no label row.
11
13
  *
12
14
  * Borders on column C (the gray bar) are driven by `topBorder` and
13
15
  * `bottomBorder` so the caller can express "this block is the first/last
@@ -15,21 +17,25 @@ import { exerciseNameStyle, groupLabelStyle, NOTES_CELL, weekRepsCellStyle, week
15
17
  *
16
18
  * @returns the next free row after the block.
17
19
  */
18
- export function stampExercise(ws, startRow, exercise, opts) {
20
+ export function stampExercise(ws, startRow, exercise, layout, opts) {
21
+ const { repsCols: WEEK_REPS_COLS, weightCols: WEEK_WEIGHT_COLS, notesCol: NOTES_COL } = layout;
19
22
  const setCount = exercise.sets.length;
20
- const hasGroupLabel = exercise.groupLabel !== undefined;
21
- const lastBlockRow = startRow + setCount - 1;
23
+ const hasGroupLabel = opts.label !== undefined;
24
+ // The label shares the last set's row; a one-set block gets an extra row
25
+ // for it, left empty of prescriptions.
26
+ const rowCount = hasGroupLabel && setCount === 1 ? 2 : setCount;
27
+ const lastBlockRow = startRow + rowCount - 1;
22
28
  // Where the exercise-name region ends.
23
- const nameLastRow = hasGroupLabel && setCount > 1 ? lastBlockRow - 1 : lastBlockRow;
29
+ const nameLastRow = hasGroupLabel ? lastBlockRow - 1 : lastBlockRow;
24
30
  if (nameLastRow > startRow) {
25
31
  ws.mergeCells(`${EXERCISE_NAME_COL}${startRow}:${EXERCISE_NAME_COL}${nameLastRow}`);
26
32
  }
27
33
  const nameCell = ws.getCell(`${EXERCISE_NAME_COL}${startRow}`);
28
34
  nameCell.value = exercise.name;
29
35
  Object.assign(nameCell, exerciseNameStyle(opts.topBorder));
30
- if (hasGroupLabel && setCount > 1) {
36
+ if (hasGroupLabel) {
31
37
  const groupCell = ws.getCell(`${EXERCISE_NAME_COL}${lastBlockRow}`);
32
- groupCell.value = exercise.groupLabel;
38
+ groupCell.value = opts.label;
33
39
  Object.assign(groupCell, groupLabelStyle(opts.bottomBorder));
34
40
  }
35
41
  else if (!hasGroupLabel && opts.bottomBorder === "medium") {
@@ -44,27 +50,28 @@ export function stampExercise(ws, startRow, exercise, opts) {
44
50
  };
45
51
  Object.assign(nameCell, composed);
46
52
  }
47
- // Notes column P: merge across the whole block when there's more than one row.
48
- if (setCount > 1) {
53
+ // Notes column: merge across the whole block when there's more than one row.
54
+ if (rowCount > 1) {
49
55
  ws.mergeCells(`${NOTES_COL}${startRow}:${NOTES_COL}${lastBlockRow}`);
50
56
  }
51
57
  const noteCell = ws.getCell(`${NOTES_COL}${startRow}`);
52
58
  noteCell.value = exercise.notes ?? "";
53
59
  Object.assign(noteCell, NOTES_CELL);
54
60
  // Per-set per-week cells
55
- for (let setIdx = 0; setIdx < setCount; setIdx++) {
61
+ for (let setIdx = 0; setIdx < rowCount; setIdx++) {
56
62
  const r = startRow + setIdx;
57
63
  const isTop = setIdx === 0;
58
- const isBottom = setIdx === setCount - 1;
59
- const setRow = exercise.sets[setIdx];
60
- for (let weekIdx = 0; weekIdx < 6; weekIdx++) {
64
+ const isBottom = setIdx === rowCount - 1;
65
+ const setRow = exercise.sets[setIdx] ?? [];
66
+ const weightRow = exercise.weights?.[setIdx];
67
+ for (let weekIdx = 0; weekIdx < layout.weekCount; weekIdx++) {
61
68
  const repsCol = WEEK_REPS_COLS[weekIdx];
62
69
  const weightCol = WEEK_WEIGHT_COLS[weekIdx];
63
70
  const repsCell = ws.getCell(`${repsCol}${r}`);
64
71
  repsCell.value = setRow[weekIdx] ?? null;
65
72
  Object.assign(repsCell, weekRepsCellStyle({ isTop, isBottom }));
66
73
  const weightCell = ws.getCell(`${weightCol}${r}`);
67
- weightCell.value = null;
74
+ weightCell.value = weightRow?.[weekIdx] ?? null;
68
75
  Object.assign(weightCell, weekWeightCellStyle({ isTop, isBottom }));
69
76
  }
70
77
  }
@@ -1 +1 @@
1
- {"version":3,"file":"stamp-exercise.js","sourceRoot":"","sources":["../../src/writer/stamp-exercise.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stamp-exercise.js","sourceRoot":"","sources":["../../src/writer/stamp-exercise.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAmB,MAAM,aAAa,CAAC;AACjE,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,UAAU,EACV,iBAAiB,EACjB,mBAAmB,GAGpB,MAAM,aAAa,CAAC;AAiBrB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,aAAa,CAC3B,EAAqB,EACrB,QAAgB,EAChB,QAAkB,EAClB,MAAkB,EAClB,IAAkB;IAElB,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IAC/F,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;IACtC,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC;IAC/C,yEAAyE;IACzE,uCAAuC;IACvC,MAAM,QAAQ,GAAG,aAAa,IAAI,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAChE,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,CAAC,CAAC;IAE7C,uCAAuC;IACvC,MAAM,WAAW,GAAG,aAAa,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;IAEpE,IAAI,WAAW,GAAG,QAAQ,EAAE,CAAC;QAC3B,EAAE,CAAC,UAAU,CACX,GAAG,iBAAiB,GAAG,QAAQ,IAAI,iBAAiB,GAAG,WAAW,EAAE,CACrE,CAAC;IACJ,CAAC;IACD,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,iBAAiB,GAAG,QAAQ,EAAE,CAAC,CAAC;IAC/D,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC;IAC/B,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAE3D,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,SAAS,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,iBAAiB,GAAG,YAAY,EAAE,CAAC,CAAC;QACpE,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC,KAAM,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,eAAe,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;IAC/D,CAAC;SAAM,IAAI,CAAC,aAAa,IAAI,IAAI,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;QAC5D,sEAAsE;QACtE,6DAA6D;QAC7D,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACnD,wEAAwE;QACxE,sDAAsD;QACtD,QAAQ,CAAC,MAAM,GAAG;YAChB,GAAG,QAAQ,CAAC,MAAM;YAClB,MAAM,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAA8B,EAAE;SAC7D,CAAC;QACrB,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED,6EAA6E;IAC7E,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;QACjB,EAAE,CAAC,UAAU,CAAC,GAAG,SAAS,GAAG,QAAQ,IAAI,SAAS,GAAG,YAAY,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,SAAS,GAAG,QAAQ,EAAE,CAAC,CAAC;IACvD,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC;IACtC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAEpC,yBAAyB;IACzB,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC;QACjD,MAAM,CAAC,GAAG,QAAQ,GAAG,MAAM,CAAC;QAC5B,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM,KAAK,QAAQ,GAAG,CAAC,CAAC;QACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC3C,MAAM,SAAS,GAAG,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;QAE7C,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,CAAC;YAC5D,MAAM,OAAO,GAAG,cAAc,CAAC,OAAO,CAAE,CAAC;YACzC,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAE,CAAC;YAE7C,MAAM,QAAQ,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,OAAO,GAAG,CAAC,EAAE,CAAC,CAAC;YAC9C,QAAQ,CAAC,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;YACzC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,iBAAiB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;YAEhE,MAAM,UAAU,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC,CAAC;YAClD,UAAU,CAAC,KAAK,GAAG,SAAS,EAAE,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;YAChD,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,mBAAmB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,OAAO,YAAY,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,aAAa,CAAC,KAAyB;IACrD,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9B,CAAC"}
@@ -1,10 +1,11 @@
1
1
  import type ExcelJS from "exceljs";
2
2
  import type { SupplementalNote } from "../schema/program.js";
3
+ import { type WeekLayout } from "./layout.js";
3
4
  /**
4
5
  * Stamps the fixed "Sport Specific / Supplemental" template area at the
5
6
  * bottom of a day sheet, then layers in any supplementalNotes the program
6
7
  * JSON supplied. The template is 10 rows tall and uses single-row merges
7
- * in each week-column pair (D-E, F-G, H-I, J-K, L-M, N-O) so the LLM can
8
+ * in each week-column pair (D-E, F-G, … one pair per week) so the LLM can
8
9
  * put a value into any cell by its master address.
9
10
  *
10
11
  * Layout:
@@ -19,5 +20,5 @@ import type { SupplementalNote } from "../schema/program.js";
19
20
  *
20
21
  * @returns the next free row after the template (startRow + 10).
21
22
  */
22
- export declare function stampSupplementalTemplate(ws: ExcelJS.Worksheet, startRow: number, supplementalNotes?: SupplementalNote[]): number;
23
+ export declare function stampSupplementalTemplate(ws: ExcelJS.Worksheet, startRow: number, layout: WeekLayout, supplementalNotes?: SupplementalNote[]): number;
23
24
  //# sourceMappingURL=supplemental-template.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"supplemental-template.d.ts","sourceRoot":"","sources":["../../src/writer/supplemental-template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAkB7D;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,OAAO,CAAC,SAAS,EACrB,QAAQ,EAAE,MAAM,EAChB,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,GACrC,MAAM,CAiER"}
1
+ {"version":3,"file":"supplemental-template.d.ts","sourceRoot":"","sources":["../../src/writer/supplemental-template.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAYjE;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,OAAO,CAAC,SAAS,EACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,EAClB,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,GACrC,MAAM,CAkER"}
@@ -1,4 +1,4 @@
1
- import { EXERCISE_NAME_COL, NOTES_COL, WEEK_REPS_COLS, WEEK_WEIGHT_COLS, } from "./layout.js";
1
+ import { EXERCISE_NAME_COL } from "./layout.js";
2
2
  import { TPL_C_GRAY, TPL_C_GRAY_BOTTOM, TPL_NOTES_LEFT, TPL_NOTES_LEFT_BOTTOM, } from "./styles.js";
3
3
  const TEMPLATE_ROWS = 10;
4
4
  const LABEL_SPORT_SPECIFIC_ROW = 0;
@@ -7,7 +7,7 @@ const LABEL_SUPPLEMENTAL_ROW = 1;
7
7
  * Stamps the fixed "Sport Specific / Supplemental" template area at the
8
8
  * bottom of a day sheet, then layers in any supplementalNotes the program
9
9
  * JSON supplied. The template is 10 rows tall and uses single-row merges
10
- * in each week-column pair (D-E, F-G, H-I, J-K, L-M, N-O) so the LLM can
10
+ * in each week-column pair (D-E, F-G, … one pair per week) so the LLM can
11
11
  * put a value into any cell by its master address.
12
12
  *
13
13
  * Layout:
@@ -22,7 +22,8 @@ const LABEL_SUPPLEMENTAL_ROW = 1;
22
22
  *
23
23
  * @returns the next free row after the template (startRow + 10).
24
24
  */
25
- export function stampSupplementalTemplate(ws, startRow, supplementalNotes) {
25
+ export function stampSupplementalTemplate(ws, startRow, layout, supplementalNotes) {
26
+ const { weekCount, repsCols: WEEK_REPS_COLS, weightCols: WEEK_WEIGHT_COLS, notesCol: NOTES_COL } = layout;
26
27
  const lastTemplateRow = startRow + TEMPLATE_ROWS - 1;
27
28
  // --- Column C: gray bar with labels at the top two rows. ---
28
29
  for (let i = 0; i < TEMPLATE_ROWS; i++) {
@@ -36,37 +37,37 @@ export function stampSupplementalTemplate(ws, startRow, supplementalNotes) {
36
37
  c.value = null;
37
38
  Object.assign(c, i === TEMPLATE_ROWS - 1 ? TPL_C_GRAY_BOTTOM : TPL_C_GRAY);
38
39
  }
39
- // --- Week-column content cells: each week pair (D-E, F-G, …, N-O) is
40
+ // --- Week-column content cells: each week pair (D-E, F-G, …) is
40
41
  // merged into a single master cell per row, matching the source files.
41
42
  // Merging (plus wrapText on the style) lets a long phrase wrap inside
42
43
  // the cell instead of clipping at the D/E boundary. Each cell is
43
44
  // plain-white-filled. Borders are only on the "reps" columns
44
- // (D/F/H/J/L/N) and on O so the rendered area has:
45
+ // and on the last weight column so the rendered area has:
45
46
  // - a left edge on D
46
- // - 5 vertical dividers between adjacent week pairs (E|F, G|H, …)
47
- // - a right edge on O
47
+ // - a vertical divider between adjacent week pairs (E|F, G|H, …)
48
+ // - a right edge on the last weight column
48
49
  // - top edge on row 0, bottom edge on row 9
49
50
  // No horizontal lines between content rows.
50
51
  for (let i = 0; i < TEMPLATE_ROWS; i++) {
51
52
  const r = startRow + i;
52
53
  const isTop = i === 0;
53
54
  const isBottom = i === TEMPLATE_ROWS - 1;
54
- for (let w = 0; w < 6; w++) {
55
+ for (let w = 0; w < weekCount; w++) {
55
56
  const left = WEEK_REPS_COLS[w];
56
57
  const right = WEEK_WEIGHT_COLS[w];
57
- const isLastPair = w === 5;
58
+ const isLastPair = w === weekCount - 1;
58
59
  ws.mergeCells(`${left}${r}:${right}${r}`);
59
60
  Object.assign(ws.getCell(`${left}${r}`), contentCellStyle({ side: "left", isTop, isBottom, isLastPair: false }));
60
61
  Object.assign(ws.getCell(`${right}${r}`), contentCellStyle({ side: "right", isTop, isBottom, isLastPair }));
61
62
  }
62
63
  }
63
- // --- Notes column P: open above, closed at the bottom. ---
64
+ // --- Notes column: open above, closed at the bottom. ---
64
65
  for (let i = 0; i < TEMPLATE_ROWS; i++) {
65
66
  const r = startRow + i;
66
67
  Object.assign(ws.getCell(`${NOTES_COL}${r}`), i === TEMPLATE_ROWS - 1 ? TPL_NOTES_LEFT_BOTTOM : TPL_NOTES_LEFT);
67
68
  }
68
69
  // --- Apply supplementalNotes on top of the template. Each note's col is a
69
- // week-pair master (D, F, H, J, L, N), so writing to it fills the
70
+ // week-pair master (D, F, H, …), so writing to it fills the
70
71
  // merged cell. ---
71
72
  if (supplementalNotes) {
72
73
  for (const note of supplementalNotes) {
@@ -95,10 +96,9 @@ function contentCellStyle(opts) {
95
96
  // the outer left edge of the whole area.
96
97
  if (opts.side === "left")
97
98
  border.left = MEDIUM;
98
- // The "right" cell of the LAST week pair (O) carries the right edge of
99
- // the whole area. Other "right" cells (E, G, I, K, M) carry no right
100
- // border — the divider to the next pair is provided by THAT pair's left
101
- // cell (F, H, J, L, N).
99
+ // The "right" cell of the LAST week pair carries the right edge of the
100
+ // whole area. Other "right" cells carry no right border — the divider to
101
+ // the next pair is provided by THAT pair's left cell.
102
102
  if (opts.side === "right" && opts.isLastPair)
103
103
  border.right = MEDIUM;
104
104
  if (opts.isTop)
@@ -1 +1 @@
1
- {"version":3,"file":"supplemental-template.js","sourceRoot":"","sources":["../../src/writer/supplemental-template.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"supplemental-template.js","sourceRoot":"","sources":["../../src/writer/supplemental-template.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workingdevshero/olympia-ait-adapter",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "MCP adapter that converts between Olympia Fitness & Performance XLSX workbooks (programs and companion warm-ups) and strict JSON schemas.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -47,27 +47,43 @@ JSON shape (zod-validated; every tool call re-validates):
47
47
  Program { client, programDate, days[] }
48
48
  Day { name, sections[], supplementalNotes?[] }
49
49
  Section { kind: "warmup"|"main"|"sportSpecific"|"supplemental"|"conditioning", exercises[] }
50
- Exercise { name, groupLabel?, notes?, sets[][] } // sets[setIdx][weekIdx], inner length 6
50
+ Exercise { name, groupLabel?, notes?, sets[][], weights?[][] } // [setIdx][weekIdx], one entry per week
51
51
  ```
52
52
 
53
53
  - One sheet per day; sheet name = day name (`"Day 1"`).
54
- - Six-week grid: every set row has exactly 6 cells, one per week, in week
55
- order. Set positions are coherent across weeks (`sets[0]` is set 1's
54
+ - Week grid: a program runs a fixed number of weeks, 4 or 6 at Olympia
55
+ (1-6 accepted). Every set row has one cell per week, in week order, and
56
+ every set row in the program must be the same length. Decoding a client's
57
+ past program tells you their week count — author the new program with the
58
+ same count; the sheet is laid out with exactly that many week columns.
59
+ Set positions are coherent across weeks (`sets[0]` is set 1's
56
60
  progression).
57
61
  - `groupLabel` matches `/^\d+[A-Z]$/`. Same number = one superset/circuit
58
62
  group (1A/1B run back-to-back).
59
63
  - Cell notation: `"12"` (reps), `"10E"` (each side), `":20"` (20-sec hold),
60
64
  `":20E"`, `":60"`, `"5 breaths"`, or freeform circuit strings like
61
- `"x3 Rest :60"`. Weights are **never** prescribed; `null` = empty cell.
65
+ `"x3 Rest :60"`. `null` = empty cell.
66
+ - `weights` is the Weight column beside each reps cell, same shape as
67
+ `sets` (`weights[setIdx][weekIdx]`). Cells are free text and most are
68
+ empty, because the client writes in what they lifted. Coaches type a
69
+ starting load (`"25"`) or an equipment setting — band colour (`"Yel"`),
70
+ box height (`'12" + 2 Pads'`), rack position (`"#10"`) — usually in
71
+ week 1 only. A bodyweight exercise may have empty reps and a setting in
72
+ every Weight cell. Omit `weights` when every cell is empty.
62
73
  - The row-2 `Date:` cells are **intentionally blank** — clients hand-write
63
74
  week dates. Never author values for them.
64
- - `Section.kind: "warmup"` is the short warmup row *inside* a program day
65
- sheet. It is unrelated to the companion warm-up workbook.
75
+ - `Section.kind: "warmup"` holds warm-up exercises listed *inside* a
76
+ program day sheet, above the main exercises. On the sheet each one is
77
+ closed by a "Warmup N" label row where a main exercise has its group
78
+ label, so give them no `groupLabel`. One set is fine. It is
79
+ unrelated to the companion warm-up workbook.
66
80
  - `supplementalNotes` is the freeform trainer-managed area at the bottom of
67
81
  a day sheet: sparse `{ row, col, value }` entries where `row` is the
68
- offset from the area's first row and `col` is one of the week-column
69
- masters `D/F/H/J/L/N`. One full phrase per row; to span the row visually,
70
- repeat the same `value` in each of the six columns.
82
+ offset from the area's first row and `col` is a week-column master:
83
+ `D/F/H/J` for a 4-week program, plus `L/N` for a 6-week one. Any other
84
+ column is rejected. One full
85
+ phrase per row; to span the row visually,
86
+ repeat the same `value` in each week column.
71
87
 
72
88
  ## Warm-up format
73
89