ima-claude 2.9.0 → 2.13.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/README.md +20 -15
- package/dist/cli.js +385 -17
- package/package.json +1 -1
- package/platforms/gemini/adapter.ts +443 -0
- package/platforms/gemini/gemini-extension.json +17 -0
- package/platforms/gemini/hooks-translator.py +66 -0
- package/platforms/shared/detector.ts +5 -1
- package/plugins/ima-claude/.claude-plugin/plugin.json +2 -2
- package/plugins/ima-claude/skills/gh-cli/SKILL.md +286 -0
- package/plugins/ima-claude/skills/ima-doc2pdf/SKILL.md +242 -0
- package/plugins/ima-claude/skills/ima-doc2pdf/references/formatting-spec.md +88 -0
- package/plugins/ima-claude/skills/ima-doc2pdf/scripts/docx_utils.py +21 -0
- package/plugins/ima-claude/skills/ima-doc2pdf/scripts/extract_docx.py +384 -0
- package/plugins/ima-claude/skills/ima-doc2pdf/scripts/generate_pdf.py +663 -0
- package/plugins/ima-claude/skills/mcp-gitea/SKILL.md +358 -0
- package/plugins/ima-claude/skills/mcp-github/SKILL.md +200 -0
- package/plugins/ima-claude/skills/mcp-qdrant/SKILL.md +21 -10
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gh-cli
|
|
3
|
+
description: >-
|
|
4
|
+
GitHub CLI (gh) for pull requests, issues, releases, Actions, code review, and repo
|
|
5
|
+
management. Primary tool for GitHub operations — reliable, fast, always available.
|
|
6
|
+
Use when: creating PRs, reviewing PRs, managing issues, checking CI status, creating
|
|
7
|
+
releases, searching GitHub, or any github.com operation. Triggers on: GitHub, gh,
|
|
8
|
+
pull request, PR, issue, release, actions, workflow, CI status, code review, merge PR.
|
|
9
|
+
NOT for Gitea — use mcp-gitea for internal repos.
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# GitHub CLI (`gh`) — GitHub Operations
|
|
13
|
+
|
|
14
|
+
The `gh` CLI is the primary tool for all GitHub operations. It's authenticated, reliable, and covers the full GitHub API surface.
|
|
15
|
+
|
|
16
|
+
## Prerequisites
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Verify authentication
|
|
20
|
+
gh auth status
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The CLI must be authenticated (`gh auth login`) before use. Verify scopes with `gh auth status`.
|
|
24
|
+
|
|
25
|
+
## Command Reference
|
|
26
|
+
|
|
27
|
+
### Pull Requests
|
|
28
|
+
|
|
29
|
+
| Operation | Command |
|
|
30
|
+
|-----------|---------|
|
|
31
|
+
| Create PR | `gh pr create --title "..." --body "..." --base main` |
|
|
32
|
+
| Create PR (fill from commits) | `gh pr create --fill` |
|
|
33
|
+
| Create draft PR | `gh pr create --draft --title "..." --body "..."` |
|
|
34
|
+
| List open PRs | `gh pr list` |
|
|
35
|
+
| List PRs by state | `gh pr list --state closed` |
|
|
36
|
+
| List PRs by author | `gh pr list --author "@me"` |
|
|
37
|
+
| List PRs by label | `gh pr list --label "bug"` |
|
|
38
|
+
| View PR details | `gh pr view 123` |
|
|
39
|
+
| View PR in browser | `gh pr view 123 --web` |
|
|
40
|
+
| View PR diff | `gh pr diff 123` |
|
|
41
|
+
| Check CI status | `gh pr checks 123` |
|
|
42
|
+
| Checkout PR locally | `gh pr checkout 123` |
|
|
43
|
+
| Merge PR (squash) | `gh pr merge 123 --squash` |
|
|
44
|
+
| Merge PR (rebase) | `gh pr merge 123 --rebase` |
|
|
45
|
+
| Merge PR (merge commit) | `gh pr merge 123 --merge` |
|
|
46
|
+
| Merge + delete branch | `gh pr merge 123 --squash --delete-branch` |
|
|
47
|
+
| Close PR | `gh pr close 123` |
|
|
48
|
+
| Reopen PR | `gh pr reopen 123` |
|
|
49
|
+
| Edit PR | `gh pr edit 123 --title "..." --body "..."` |
|
|
50
|
+
| Add reviewer | `gh pr edit 123 --add-reviewer username` |
|
|
51
|
+
| Add label | `gh pr edit 123 --add-label "bug"` |
|
|
52
|
+
| Mark as ready | `gh pr ready 123` |
|
|
53
|
+
| Comment on PR | `gh pr comment 123 --body "..."` |
|
|
54
|
+
| Review PR (approve) | `gh pr review 123 --approve --body "LGTM"` |
|
|
55
|
+
| Review PR (request changes) | `gh pr review 123 --request-changes --body "..."` |
|
|
56
|
+
| Review PR (comment only) | `gh pr review 123 --comment --body "..."` |
|
|
57
|
+
| My PR status | `gh pr status` |
|
|
58
|
+
|
|
59
|
+
### Issues
|
|
60
|
+
|
|
61
|
+
| Operation | Command |
|
|
62
|
+
|-----------|---------|
|
|
63
|
+
| Create issue | `gh issue create --title "..." --body "..."` |
|
|
64
|
+
| Create issue with labels | `gh issue create --title "..." --label "bug" --label "priority"` |
|
|
65
|
+
| Create issue with assignee | `gh issue create --title "..." --assignee "@me"` |
|
|
66
|
+
| List open issues | `gh issue list` |
|
|
67
|
+
| List by state | `gh issue list --state closed` |
|
|
68
|
+
| List by label | `gh issue list --label "bug"` |
|
|
69
|
+
| List by assignee | `gh issue list --assignee "@me"` |
|
|
70
|
+
| View issue | `gh issue view 42` |
|
|
71
|
+
| View in browser | `gh issue view 42 --web` |
|
|
72
|
+
| Close issue | `gh issue close 42` |
|
|
73
|
+
| Close with comment | `gh issue close 42 --comment "Fixed in v2.11.0"` |
|
|
74
|
+
| Reopen issue | `gh issue reopen 42` |
|
|
75
|
+
| Comment on issue | `gh issue comment 42 --body "..."` |
|
|
76
|
+
| Edit issue | `gh issue edit 42 --title "..." --body "..."` |
|
|
77
|
+
| Add label | `gh issue edit 42 --add-label "in-progress"` |
|
|
78
|
+
| Remove label | `gh issue edit 42 --remove-label "triage"` |
|
|
79
|
+
| Assign | `gh issue edit 42 --add-assignee username` |
|
|
80
|
+
| Pin issue | `gh issue pin 42` |
|
|
81
|
+
| Transfer issue | `gh issue transfer 42 owner/other-repo` |
|
|
82
|
+
| My issue status | `gh issue status` |
|
|
83
|
+
|
|
84
|
+
### Repositories
|
|
85
|
+
|
|
86
|
+
| Operation | Command |
|
|
87
|
+
|-----------|---------|
|
|
88
|
+
| View repo | `gh repo view owner/name` |
|
|
89
|
+
| View in browser | `gh repo view --web` |
|
|
90
|
+
| Clone repo | `gh repo clone owner/name` |
|
|
91
|
+
| Fork repo | `gh repo fork owner/name` |
|
|
92
|
+
| Create repo | `gh repo create name --public --description "..."` |
|
|
93
|
+
| Create private repo | `gh repo create name --private` |
|
|
94
|
+
| List my repos | `gh repo list` |
|
|
95
|
+
| List org repos | `gh repo list org-name` |
|
|
96
|
+
| Sync fork | `gh repo sync owner/name` |
|
|
97
|
+
| Set default repo | `gh repo set-default owner/name` |
|
|
98
|
+
|
|
99
|
+
### Releases & Tags
|
|
100
|
+
|
|
101
|
+
| Operation | Command |
|
|
102
|
+
|-----------|---------|
|
|
103
|
+
| Create release | `gh release create v1.0.0 --title "v1.0.0" --notes "..."` |
|
|
104
|
+
| Create draft release | `gh release create v1.0.0 --draft --title "v1.0.0" --notes "..."` |
|
|
105
|
+
| Create release from tag | `gh release create v1.0.0 --generate-notes` |
|
|
106
|
+
| Upload assets | `gh release upload v1.0.0 ./dist/*.tar.gz` |
|
|
107
|
+
| List releases | `gh release list` |
|
|
108
|
+
| View release | `gh release view v1.0.0` |
|
|
109
|
+
| Download assets | `gh release download v1.0.0` |
|
|
110
|
+
| Delete release | `gh release delete v1.0.0` |
|
|
111
|
+
| Edit release | `gh release edit v1.0.0 --title "..." --notes "..."` |
|
|
112
|
+
|
|
113
|
+
### GitHub Actions (Workflows & Runs)
|
|
114
|
+
|
|
115
|
+
| Operation | Command |
|
|
116
|
+
|-----------|---------|
|
|
117
|
+
| List workflows | `gh workflow list` |
|
|
118
|
+
| View workflow | `gh workflow view workflow-name` |
|
|
119
|
+
| Run workflow | `gh workflow run workflow-name` |
|
|
120
|
+
| Run with inputs | `gh workflow run workflow-name -f key=value` |
|
|
121
|
+
| Disable workflow | `gh workflow disable workflow-name` |
|
|
122
|
+
| Enable workflow | `gh workflow enable workflow-name` |
|
|
123
|
+
| List recent runs | `gh run list` |
|
|
124
|
+
| List runs for workflow | `gh run list --workflow workflow-name` |
|
|
125
|
+
| View run details | `gh run view 12345` |
|
|
126
|
+
| View run logs | `gh run view 12345 --log` |
|
|
127
|
+
| Watch run progress | `gh run watch 12345` |
|
|
128
|
+
| Download artifacts | `gh run download 12345` |
|
|
129
|
+
| Rerun failed jobs | `gh run rerun 12345 --failed` |
|
|
130
|
+
| Cancel run | `gh run cancel 12345` |
|
|
131
|
+
|
|
132
|
+
### Search (Cross-Repository)
|
|
133
|
+
|
|
134
|
+
| Operation | Command |
|
|
135
|
+
|-----------|---------|
|
|
136
|
+
| Search repos | `gh search repos "query" --sort stars` |
|
|
137
|
+
| Search issues | `gh search issues "query" --repo owner/name` |
|
|
138
|
+
| Search PRs | `gh search prs "query" --state open` |
|
|
139
|
+
| Search code | `gh search code "pattern" --repo owner/name` |
|
|
140
|
+
| Search commits | `gh search commits "query" --repo owner/name` |
|
|
141
|
+
|
|
142
|
+
### Labels
|
|
143
|
+
|
|
144
|
+
| Operation | Command |
|
|
145
|
+
|-----------|---------|
|
|
146
|
+
| List labels | `gh label list` |
|
|
147
|
+
| Create label | `gh label create "name" --color "0075ca" --description "..."` |
|
|
148
|
+
| Edit label | `gh label edit "name" --new-name "..." --color "..."` |
|
|
149
|
+
| Delete label | `gh label delete "name" --yes` |
|
|
150
|
+
| Clone labels to another repo | `gh label clone source-owner/source-repo` |
|
|
151
|
+
|
|
152
|
+
### Raw API Access
|
|
153
|
+
|
|
154
|
+
For operations not covered by built-in commands:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
# GET request
|
|
158
|
+
gh api repos/{owner}/{repo}/topics
|
|
159
|
+
|
|
160
|
+
# POST request
|
|
161
|
+
gh api repos/{owner}/{repo}/labels -f name="priority" -f color="ff0000"
|
|
162
|
+
|
|
163
|
+
# With pagination
|
|
164
|
+
gh api repos/{owner}/{repo}/issues --paginate
|
|
165
|
+
|
|
166
|
+
# GraphQL
|
|
167
|
+
gh api graphql -f query='{ viewer { login } }'
|
|
168
|
+
|
|
169
|
+
# JSON output + jq filtering
|
|
170
|
+
gh api repos/{owner}/{repo}/pulls --jq '.[].title'
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Decision Logic
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
Is this a GitHub-hosted repo?
|
|
177
|
+
Check: git remote -v → shows github.com
|
|
178
|
+
→ Yes: Use gh CLI (this skill)
|
|
179
|
+
→ No: Is it Gitea-hosted?
|
|
180
|
+
→ Yes: Use mcp-gitea tools (see mcp-gitea skill)
|
|
181
|
+
→ Unknown: Ask the user
|
|
182
|
+
|
|
183
|
+
For local-only git operations (commit, diff, log, stash, rebase):
|
|
184
|
+
→ Always use git CLI directly — gh is for GitHub API operations
|
|
185
|
+
|
|
186
|
+
Operation routing:
|
|
187
|
+
PRs (create, review, merge, list) → gh pr ...
|
|
188
|
+
Issues (create, comment, close) → gh issue ...
|
|
189
|
+
Releases (create, upload, list) → gh release ...
|
|
190
|
+
CI/CD status, rerun, logs → gh run ... / gh workflow ...
|
|
191
|
+
Search across GitHub → gh search ...
|
|
192
|
+
Anything not in built-in commands → gh api ...
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Common Workflows
|
|
196
|
+
|
|
197
|
+
### Create a PR with Body via HEREDOC
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
gh pr create --title "feat: add gh-cli skill" --body "$(cat <<'EOF'
|
|
201
|
+
## Summary
|
|
202
|
+
- Added gh-cli skill for GitHub CLI operations
|
|
203
|
+
- Replaces unreliable MCP GitHub integration
|
|
204
|
+
|
|
205
|
+
## Test plan
|
|
206
|
+
- [ ] Verify gh auth status
|
|
207
|
+
- [ ] Test PR creation workflow
|
|
208
|
+
EOF
|
|
209
|
+
)"
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Check CI and Merge When Ready
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
# Check CI status
|
|
216
|
+
gh pr checks 123
|
|
217
|
+
|
|
218
|
+
# If all checks pass, merge
|
|
219
|
+
gh pr merge 123 --squash --delete-branch
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Create a Release with Changelog
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
gh release create v2.12.0 \
|
|
226
|
+
--title "v2.12.0 — Add gh-cli skill" \
|
|
227
|
+
--generate-notes \
|
|
228
|
+
--latest
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Cross-Repo Issue Search
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
# Find all open bugs assigned to me across repos
|
|
235
|
+
gh search issues "is:open assignee:@me label:bug" --limit 20
|
|
236
|
+
|
|
237
|
+
# Find PRs awaiting my review
|
|
238
|
+
gh search prs "is:open review-requested:@me" --limit 20
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### View PR Comments (API)
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
# List PR review comments
|
|
245
|
+
gh api repos/{owner}/{repo}/pulls/123/comments --jq '.[].body'
|
|
246
|
+
|
|
247
|
+
# List issue/PR timeline comments
|
|
248
|
+
gh api repos/{owner}/{repo}/issues/123/comments --jq '.[] | "\(.user.login): \(.body)"'
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Output Formatting
|
|
252
|
+
|
|
253
|
+
The `gh` CLI supports structured output:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# JSON output
|
|
257
|
+
gh pr list --json number,title,state
|
|
258
|
+
|
|
259
|
+
# JSON + jq filter
|
|
260
|
+
gh pr list --json number,title --jq '.[] | "\(.number): \(.title)"'
|
|
261
|
+
|
|
262
|
+
# Table format (default for list commands)
|
|
263
|
+
gh issue list
|
|
264
|
+
|
|
265
|
+
# Web browser
|
|
266
|
+
gh pr view 123 --web
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Cross-Repository Operations
|
|
270
|
+
|
|
271
|
+
Use `--repo` or `-R` to target any GitHub repo:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
gh pr list -R owner/other-repo
|
|
275
|
+
gh issue create -R owner/other-repo --title "..."
|
|
276
|
+
gh run list -R owner/other-repo
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## When NOT to Use
|
|
280
|
+
|
|
281
|
+
| Situation | Use Instead |
|
|
282
|
+
|-----------|-------------|
|
|
283
|
+
| Gitea-hosted repos | `mcp-gitea` tools |
|
|
284
|
+
| Local git operations (commit, diff, stash) | `git` CLI directly |
|
|
285
|
+
| Reading local files | Read tool |
|
|
286
|
+
| Pushing/pulling code | `git push` / `git pull` |
|
|
@@ -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
|