ima-claude 2.9.0 → 2.10.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/dist/cli.js CHANGED
@@ -11,7 +11,7 @@ var HOOKS_DIR = join(CLAUDE_DIR, "hooks");
11
11
  var COMMANDS_DIR = join(CLAUDE_DIR, "commands");
12
12
  var RULES_DIR = join(CLAUDE_DIR, "rules");
13
13
  var SETTINGS_FILE = join(CLAUDE_DIR, "settings.json");
14
- var VERSION = "2.9.0";
14
+ var VERSION = "2.10.0";
15
15
  var colors = {
16
16
  reset: "\x1B[0m",
17
17
  bright: "\x1B[1m",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ima-claude",
3
- "version": "2.9.0",
3
+ "version": "2.10.0",
4
4
  "description": "IMA's AI coding agent skills - FP patterns, architecture guidance, and team standards. Supports Claude Code, Junie CLI, and more.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ima-claude",
3
- "version": "2.9.0",
3
+ "version": "2.10.0",
4
4
  "description": "IMA's Claude Code skills for functional programming, architecture, and team standards. 47 skills, 24 hooks, default persona, 3-tier memory system.",
5
5
  "author": {
6
6
  "name": "IMA",
@@ -0,0 +1,242 @@
1
+ ---
2
+ name: ima-doc2pdf
3
+ description: >-
4
+ Convert DOCX content into branded IMA PDF documents using ReportLab with Lato
5
+ typography, navy headings, justified body text, running footers, and embedded
6
+ images. Produces branded PDF documents with content pages. Generates a placeholder
7
+ cover that can be replaced by ima-cover-creator for production output. Use when: converting a Word doc to branded PDF,
8
+ creating PDF content pages for Canva import, generating an IMA branded document PDF,
9
+ or when the user says "convert this docx to PDF," "branded PDF," "content pages,"
10
+ "PDF for Canva," or "doc to PDF." Also triggers on: "make a PDF from this Word
11
+ file," "export to PDF," "generate branded PDF," "IMA branded document PDF."
12
+ Always load ima-brand alongside for color/typography authority.
13
+ ---
14
+
15
+ # IMA DOCX → Branded PDF
16
+
17
+ Extracts content from any Word document and generates a branded IMA PDF with
18
+ Lato typography, navy/gold colors, and IMA layout standards. Works with guides,
19
+ reports, white papers, and other IMA documents. Outputs content pages only
20
+ (no cover page) — the cover is handled by `ima-cover-creator` and merged via pypdf.
21
+
22
+ ---
23
+
24
+ ## Why ReportLab for Content
25
+
26
+ Content pages are pure document flow: headings, body paragraphs, bullet lists,
27
+ inline bold/italic, embedded images, and running footers. ReportLab handles all of
28
+ this with proper Lato font registration, automatic page breaks, and precise
29
+ typographic control. No coordinate math needed — the flow engine does the work.
30
+
31
+ ---
32
+
33
+ ## Quick Start
34
+
35
+ ### 1. Install dependencies (once)
36
+
37
+ ```bash
38
+ pip install python-docx reportlab Pillow pypdf --break-system-packages
39
+ ```
40
+
41
+ ### 2. Generate content PDF
42
+
43
+ ```bash
44
+ python3 scripts/generate_pdf.py path/to/document.docx --out content.pdf
45
+ ```
46
+
47
+ ### 3. Merge with cover (from ima-cover-creator)
48
+
49
+ ```python
50
+ from pypdf import PdfReader, PdfWriter
51
+
52
+ cover = PdfReader("cover.pdf")
53
+ content = PdfReader("content.pdf")
54
+
55
+ writer = PdfWriter()
56
+ writer.add_page(cover.pages[0])
57
+
58
+ # Skip the first 2 pages (ReportLab's placeholder cover + overflow)
59
+ for page in content.pages[2:]:
60
+ writer.add_page(page)
61
+
62
+ with open("final.pdf", "wb") as f:
63
+ writer.write(f)
64
+ ```
65
+
66
+ ---
67
+
68
+ ## Pipeline
69
+
70
+ ```
71
+ DOCX
72
+ ↓ extract_docx.py (text, structure, metadata)
73
+ ↓ generate_pdf.py (ReportLab → branded PDF)
74
+
75
+ content.pdf (N pages, no cover)
76
+ +
77
+ cover.pdf (from ima-cover-creator)
78
+ ↓ pypdf merge
79
+
80
+ final.pdf → Canva import
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Typography Spec (Canva-confirmed)
86
+
87
+ All values confirmed from Canva design data. Font: Lato (Google Fonts).
88
+
89
+ ### Headings
90
+
91
+ | Element | Size | Weight | Color | Align |
92
+ |---------|------|--------|-------|-------|
93
+ | Section heading (h2) | 15pt | Bold | #00066F | Center |
94
+ | Sub-heading (h3) | 13pt | Bold | #00066F | Left |
95
+ | Intro heading | 15pt | Bold | #00066F | Center |
96
+
97
+ ### Body Text
98
+
99
+ | Element | Size | Weight | Color | Align |
100
+ |---------|------|--------|-------|-------|
101
+ | Body paragraph | 12pt | Regular | #000000 | Justify |
102
+ | Body bold inline | 12pt | Bold | #000000 | Justify |
103
+ | Body bold navy | 12pt | Bold | #00066F | Justify |
104
+ | Bullet item | 12pt | Regular | #000000 | Left |
105
+ | Bullet marker | — | — | #00066F | — |
106
+
107
+ ### Other Elements
108
+
109
+ | Element | Size | Weight | Color |
110
+ |---------|------|--------|-------|
111
+ | Footer | 10pt | Regular | #666666 |
112
+ | Reference entry | 8pt | Regular | #333333 |
113
+ | Reference heading | 13pt | Bold | #00066F |
114
+ | Q&A question | 12pt | Bold | #00066F |
115
+ | Q&A answer | 12pt | Regular | #000000 |
116
+ | Warning box | 12pt | Bold | #FFFFFF on #00066F bg |
117
+
118
+ ### Page Setup
119
+
120
+ | Property | Value |
121
+ |----------|-------|
122
+ | Page size | US Letter (8.5 × 11 in) |
123
+ | Margins | 0.5 in all sides |
124
+ | Body width | 7.5 in |
125
+ | Footer height | 0.4 in from bottom |
126
+
127
+ ---
128
+
129
+ ## Content Extraction
130
+
131
+ The `extract_docx.py` script classifies each Word paragraph into typed blocks:
132
+
133
+ | Type | Description |
134
+ |------|-------------|
135
+ | `h1` | Top-level heading (title) |
136
+ | `h2` | Section heading |
137
+ | `h3` | Sub-heading |
138
+ | `heading_bold` | All-bold paragraph (inline heading) |
139
+ | `body` | Regular paragraph |
140
+ | `bullet` | List item |
141
+ | `author` | Author name |
142
+ | `date` | Date string |
143
+ | `disclaimer` | Disclaimer text |
144
+ | `warning` | Warning box content |
145
+ | `question` | Q&A question |
146
+ | `answer_start` | Q&A answer (YES/NO prefix) |
147
+ | `reference` | Numbered citation |
148
+ | `ref_heading` | "References" heading |
149
+ | `figure_caption` | Figure/table caption |
150
+ | `page_break` | Hard page break |
151
+
152
+ Each block includes `runs` with per-run bold/italic flags for inline formatting.
153
+
154
+ ---
155
+
156
+ ## Image Handling
157
+
158
+ The script extracts embedded DOCX images via `python-docx`:
159
+
160
+ 1. Reads all image relationships from the DOCX package
161
+ 2. Maps paragraph indices to embedded image positions
162
+ 3. Writes images to temp files
163
+ 4. Inserts ReportLab `Image` flowables at the correct positions
164
+ 5. Scales to fit within `page_width - 2 × margin`
165
+
166
+ Images that appear between text paragraphs (image-only paragraphs) are also caught
167
+ and appended after all text content.
168
+
169
+ ---
170
+
171
+ ## Cover Page Behavior
172
+
173
+ The ReportLab script generates a **placeholder cover** (navy background with title
174
+ text) as pages 1-2 of its output. This exists so the script works standalone, but
175
+ when pairing with `ima-cover-creator`, **skip the first 2 pages** during merge.
176
+
177
+ To check which pages to skip:
178
+ ```python
179
+ from pypdf import PdfReader
180
+ r = PdfReader("content.pdf")
181
+ for i in range(min(3, len(r.pages))):
182
+ text = r.pages[i].extract_text()[:100]
183
+ print(f"Page {i}: {text}")
184
+ ```
185
+
186
+ The first content page typically starts with "Introduction" or a section heading.
187
+
188
+ ---
189
+
190
+ ## Scripts
191
+
192
+ | Script | Purpose |
193
+ |--------|---------|
194
+ | `generate_pdf.py` | Main: DOCX → branded PDF via ReportLab |
195
+ | `extract_docx.py` | Extracts structured content from Word documents |
196
+ | `docx_utils.py` | Shared utilities for DOCX parsing |
197
+
198
+ ---
199
+
200
+ ## Fonts
201
+
202
+ Lato TTF files are auto-downloaded from Google Fonts on first run into the `fonts/`
203
+ directory (which is git-ignored). The font family (Regular, Bold, Italic, BoldItalic)
204
+ is registered with ReportLab so that `<b>` and `<i>` markup works in Paragraph objects.
205
+
206
+ If the fonts are already present, the download is skipped.
207
+
208
+ ---
209
+
210
+ ## Customization
211
+
212
+ ### Adjusting the footer
213
+
214
+ The footer shows the document title and date. To customize:
215
+ ```python
216
+ # In generate_pdf.py, the footer text is built from:
217
+ title_short = (title[:60] + "...") if len(title) > 60 else title
218
+ footer_text = f"{title_short} ({clean_date})"
219
+ ```
220
+
221
+ ### Adding new paragraph types
222
+
223
+ 1. Add a classifier rule in `extract_docx.py`
224
+ 2. Add a handler in `block_to_flowables()` in `generate_pdf.py`
225
+ 3. Create a ReportLab `ParagraphStyle` in `build_styles()`
226
+
227
+ ---
228
+
229
+ ## Relationship to Other Skills
230
+
231
+ | Skill | Role |
232
+ |-------|------|
233
+ | **ima-cover-creator** | Generates branded cover page (PPTX → PDF) |
234
+ | **ima-cancer-care-guides** | Full pipeline including Markdown source and Canva API mapping |
235
+ | **ima-brand** | Source of truth for colors, typography, voice |
236
+
237
+ **Typical workflow:**
238
+ ```
239
+ ima-cover-creator → cover.pdf (1 page)
240
+ ima-doc2pdf → content.pdf (skip first 2 pages)
241
+ pypdf merge → final.pdf → Canva import
242
+ ```
@@ -0,0 +1,88 @@
1
+ # Content Page Formatting Spec
2
+
3
+ Values confirmed from Canva design data (Cancer Drug Resistance Guide, March 2026).
4
+ Canva internal units × 0.75 = points.
5
+
6
+ ## Page Setup
7
+
8
+ | Property | Value |
9
+ |----------|-------|
10
+ | Page size | US Letter (8.5 × 11 in / 612 × 792 pt) |
11
+ | Margins | 0.5 in (36 pt) all sides |
12
+ | Body text width | 7.5 in (540 pt) |
13
+ | Footer position | 0.4 in from bottom |
14
+
15
+ ## Color Palette
16
+
17
+ | Name | Hex | Usage |
18
+ |------|-----|-------|
19
+ | Trustworthy Indigo | #00066F | Headings, bullet markers, warning bg |
20
+ | Body Black | #000000 | Body text (pure black, not #1A1A1A) |
21
+ | Dark Gray | #333333 | Reference entries |
22
+ | Gray Text | #666666 | Footer |
23
+ | Light Gray | #CCCCCC | Footer rule |
24
+ | White | #FFFFFF | Warning text |
25
+ | Vital Gold | #FFCC00 | Warning emphasis |
26
+
27
+ ## Section Heading (h2)
28
+
29
+ - Font: Lato 15pt Bold
30
+ - Color: #00066F (navy)
31
+ - Alignment: Center
32
+ - Spacing: 16pt above, 5pt below
33
+
34
+ ## Sub-heading (h3)
35
+
36
+ - Font: Lato 13pt Bold
37
+ - Color: #00066F (navy)
38
+ - Alignment: Left
39
+ - Spacing: 10pt above, 3pt below
40
+
41
+ ## Body Paragraph
42
+
43
+ - Font: Lato 12pt Regular
44
+ - Color: #000000
45
+ - Alignment: Justify
46
+ - Line height: 1.4 (14.5pt leading)
47
+ - Spacing: 6pt below
48
+
49
+ ## Bullet Lists
50
+
51
+ - Font: Lato 12pt Regular
52
+ - Color: #000000
53
+ - Bullet marker color: #00066F (navy)
54
+ - Indent: 18pt
55
+ - Spacing: 1pt above, 1pt below each item
56
+
57
+ ## Bold Inline Variants
58
+
59
+ - **Body bold** (#000000): Drug names, emphasis
60
+ - **Body bold navy** (#00066F): Inline sub-headings
61
+
62
+ ## Warning Box
63
+
64
+ - Background: #00066F (navy) — note: ReportLab uses solid, Canva uses gradient
65
+ - Text: Lato 12pt Bold, #FFFFFF
66
+ - Emphasis: Vital Gold #FFCC00
67
+ - Alignment: Center
68
+ - Padding: 10pt all sides
69
+
70
+ ## Footer
71
+
72
+ - Font: Lato 10pt
73
+ - Color: #666666
74
+ - Alignment: Center
75
+ - Content: "{Document Title} ({Date})"
76
+ - Rule above: 0.5pt, #CCCCCC
77
+
78
+ ## References
79
+
80
+ - Heading: Lato 13pt Bold, #00066F
81
+ - Entry: Lato 8pt Regular, #333333
82
+ - Hanging indent: 14pt
83
+
84
+ ## Q&A
85
+
86
+ - Question: Lato 12pt Bold, #00066F
87
+ - Answer: Lato 12pt Regular, #000000
88
+ - YES/NO prefix: Bold
@@ -0,0 +1,21 @@
1
+ """
2
+ Shared utilities for Word document processing across ima-cancer-care-guides scripts.
3
+ """
4
+
5
+ from docx.oxml.ns import qn
6
+
7
+
8
+ def has_page_break(para):
9
+ """Detect a hard page break in a Word paragraph.
10
+
11
+ Checks both explicit w:br type=page runs and section-level page breaks
12
+ (w:pPr/w:sectPr), which appear on the last paragraph of a section.
13
+ """
14
+ for run in para.runs:
15
+ for br in run._element.findall(qn('w:br')):
16
+ if br.get(qn('w:type')) == 'page':
17
+ return True
18
+ pPr = para._element.find(qn('w:pPr'))
19
+ if pPr is not None and pPr.find(qn('w:sectPr')) is not None:
20
+ return True
21
+ return False