compono 0.1.0__tar.gz

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.
compono-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,263 @@
1
+ Metadata-Version: 2.4
2
+ Name: compono
3
+ Version: 0.1.0
4
+ Summary: Agent-oriented, code-based PPTX generation library — Manim, but for PowerPoint.
5
+ Author: Shaik-Hamzah123
6
+ Author-email: Shaik-Hamzah123 <hamzah.shaik2003@gmail.com>
7
+ License-Expression: MIT
8
+ Requires-Dist: fonttools>=4.65.0
9
+ Requires-Dist: pydantic>=2.13.5
10
+ Requires-Dist: python-pptx>=1.0.2
11
+ Requires-Dist: pyyaml>=6.0.3
12
+ Requires-Python: >=3.13
13
+ Description-Content-Type: text/markdown
14
+
15
+ # compono
16
+
17
+ **Agent-oriented, code-based PPTX generation — "Manim, but for PowerPoint."**
18
+
19
+ compono lets an LLM agent (or a human) describe a slide deck as data —
20
+ headers, bullet text, stats, tables, charts, images, process sequences,
21
+ shapes — and get back a real, editable `.pptx` file. The agent never writes
22
+ raw `x`/`y`/`w`/`h` coordinates: a constraint-based layout resolver computes
23
+ every position from a small set of typed primitives.
24
+
25
+ Every rendered element is a genuine, editable native shape (`p:sp`, `p:pic`,
26
+ `p:graphicFrame`) — never a flattened image or embedded video. Open the
27
+ result in PowerPoint and drag a box around; it's a real object, not a
28
+ picture of one.
29
+
30
+ This file is both the human-facing README and the in-context reference an
31
+ agent uses to call compono correctly — see `skills/compono/SKILL.md` for the
32
+ packaged version of the same content.
33
+
34
+ ## Install
35
+
36
+ ```bash
37
+ pip install compono # not yet published — see CHANGELOG.md for status
38
+ ```
39
+
40
+ For local development, see `CONTRIBUTING.md`.
41
+
42
+ ## Quickstart
43
+
44
+ ```python
45
+ from compono import render_deck
46
+
47
+ spec = {
48
+ "slides": [
49
+ {
50
+ "header": {"title": "Q3 Results", "subtitle": "Engineering team"},
51
+ "body": [
52
+ {
53
+ "primitive": "text",
54
+ "mode": "bullets",
55
+ "content": [
56
+ "Shipped the new layout resolver",
57
+ "Cut render time by 40%",
58
+ "Zero overflow bugs in production",
59
+ ],
60
+ "emphasis_indices": [1],
61
+ }
62
+ ],
63
+ }
64
+ ]
65
+ }
66
+
67
+ report = render_deck(spec, "deck.pptx")
68
+ print(report.pptx_path, report.warnings)
69
+ ```
70
+
71
+ Or from the command line:
72
+
73
+ ```bash
74
+ compono validate spec.json
75
+ compono render spec.json -o deck.pptx
76
+ ```
77
+
78
+ ## Core concepts
79
+
80
+ - **One entry point, two verbs.** `render_deck(spec, output_path)` and
81
+ `validate(spec)` are the only two functions you need. `validate` is cheap
82
+ — no pptx write, millisecond-scale — so an agent can iterate on a spec
83
+ before paying render cost.
84
+ - **A spec is plain data.** Either a raw `dict`/JSON (what an agent's
85
+ tool-calling naturally produces) or the typed builder classes
86
+ (`Deck`, `Header`, `Text`, ...) — both serialize to the identical shape.
87
+ There's no divergence between the two paths.
88
+ - **You never write coordinates.** Every primitive claims space in a slide;
89
+ the resolver (a CSS-flexbox-style directional box model) computes real
90
+ EMU positions. `grid` is the one primitive that does true 2D
91
+ row/column math.
92
+ - **Errors are fixes, not diagnoses.** Every validation/render failure is
93
+ `{slide, primitive, field, error, detail, fix}` — see
94
+ [Error shape](#error-shape) below.
95
+ - **render_deck returns a report, not just a file** —
96
+ `{pptx_path, manifest, warnings, actual_layout}` — so an agent can reason
97
+ about what happened without reopening the file.
98
+
99
+ ## API reference
100
+
101
+ ```python
102
+ from compono import (
103
+ render_deck, validate,
104
+ Deck, Slide, Header, Text, Image, Stat, Grid, Table, Sequence, Chart, Shape,
105
+ DeckValidationError,
106
+ )
107
+ ```
108
+
109
+ | Symbol | Signature | Notes |
110
+ |---|---|---|
111
+ | `render_deck` | `render_deck(spec, output_path, *, template=None) -> RenderReport` | Validates, resolves layout, writes a real `.pptx`. Raises `DeckValidationError` on any error — nothing is written on failure. |
112
+ | `validate` | `validate(spec, *, template=None) -> ValidationReport` | Schema + layout + text-overflow checks. No file I/O. Never raises — check `.valid`/`.errors`. |
113
+ | `DeckValidationError` | `exc.errors -> list[dict]` | The one exception type. Carries the structured error list below. |
114
+
115
+ A `Deck` is `{template?: str, slides: [Slide, ...]}`. A `Slide` is
116
+ `{header?: Header, body: [primitive, ...], notes?: str}`. `body` (and
117
+ `grid.items`) accept any primitive, keyed by its `"primitive"` field.
118
+
119
+ ### Error shape
120
+
121
+ ```json
122
+ {
123
+ "slide": 3,
124
+ "primitive": "grid.items[1]",
125
+ "field": "content",
126
+ "error": "overflow",
127
+ "detail": "Text is ~14pt too tall for the box at font size 18pt (6 lines).",
128
+ "fix": "Shorten the text, reduce bullet/line count, or split into two slides."
129
+ }
130
+ ```
131
+
132
+ ## Primitive catalog
133
+
134
+ Every primitive accepts an optional `id` (needed if another primitive
135
+ references it, e.g. a connector) and an optional `notes` (speaker notes).
136
+
137
+ | Primitive | Key fields | Purpose |
138
+ |---|---|---|
139
+ | `header` | `title`, `subtitle?`, `eyebrow?`, `align` | Slide title region. |
140
+ | `text` | `mode` (paragraph/bullets), `content`, `columns?`, `emphasis_indices?` | Prose or bullet list. |
141
+ | `image` | `src?`, `placeholder`, `caption?`, `fit` (cover/contain) | A real picture, or a first-class placeholder — see below. |
142
+ | `stat` | `value`, `label`, `trend?` | A headline number with a label. |
143
+ | `grid` | `items`, `columns`, `direction`, `align`, `justify` | The one primitive with true 2D layout. Items can be any primitive, including nested grids. |
144
+ | `table` | `headers`, `rows`, `emphasis_row?`, `emphasis_col?` | Renders as a real OOXML table (`p:graphicFrame`), not an image. |
145
+ | `sequence` | `steps` (`{label, description?}`), `orientation` | A row/column of connected step boxes — process/timeline diagrams. |
146
+ | `chart` | `chart_type` (bar/line/pie), `categories`, `series` | A real, editable native chart with live data — not a picture of a chart. |
147
+ | `shape` | `kind` (rect/rounded_rect/oval/line/arrow/connector), `fill`, `border`, `connects?`, `text?` | Freeform shape, optionally with text inside, or a connector between two other primitives by `id`. |
148
+
149
+ Every schema field's description is written as an instruction (e.g. "Keep
150
+ under ~60 characters — longer titles will be shrunk by the resolver"), not
151
+ a bare type label — call `Header.model_json_schema()` (or any primitive
152
+ class) to get the full JSON Schema with these descriptions inline.
153
+
154
+ ### Image placeholders
155
+
156
+ Set `"placeholder": true` (with an optional `caption`) instead of `src` when
157
+ you don't have a real image yet. It renders as an intentional design
158
+ element — dashed border, centered caption — and `render_deck`'s
159
+ `RenderReport.manifest` gets one entry per placeholder:
160
+ `{slide, primitive, rect: {x, y, w, h}, caption}`. A later pass (image
161
+ search/generation/human upload) can fill each reserved rect directly from
162
+ the manifest EMU rect — no re-layout needed, and the deck-building agent
163
+ itself never needs image-generation capability.
164
+
165
+ ## Worked examples
166
+
167
+ ### 1. Title slide
168
+
169
+ ```json
170
+ {
171
+ "slides": [
172
+ { "header": { "title": "2026 Roadmap", "subtitle": "Platform team", "eyebrow": "Q1 Kickoff" } }
173
+ ]
174
+ }
175
+ ```
176
+
177
+ ### 2. Two-column comparison with a connector
178
+
179
+ ```json
180
+ {
181
+ "slides": [{
182
+ "header": { "title": "Before vs. After" },
183
+ "body": [
184
+ {
185
+ "primitive": "grid",
186
+ "columns": 2,
187
+ "items": [
188
+ { "id": "before", "primitive": "shape", "kind": "rounded_rect", "fill": "#EF4444",
189
+ "text": { "content": "Manual layout" } },
190
+ { "id": "after", "primitive": "shape", "kind": "rounded_rect", "fill": "#10B981",
191
+ "text": { "content": "Resolver-computed layout" } }
192
+ ]
193
+ },
194
+ { "primitive": "shape", "kind": "connector", "connects": { "from_id": "before", "to_id": "after" } }
195
+ ]
196
+ }]
197
+ }
198
+ ```
199
+
200
+ ### 3. Stat + table + chart dashboard
201
+
202
+ ```json
203
+ {
204
+ "slides": [{
205
+ "header": { "title": "Q3 Metrics" },
206
+ "body": [
207
+ { "primitive": "stat", "value": "42%", "label": "YoY growth", "trend": "+12% vs Q2" },
208
+ { "primitive": "table", "headers": ["Quarter", "Revenue"], "rows": [["Q1", "10"], ["Q2", "14"]] },
209
+ { "primitive": "chart", "chart_type": "bar", "categories": ["Q1", "Q2"],
210
+ "series": [{ "name": "Revenue", "values": [10, 14] }] }
211
+ ]
212
+ }]
213
+ }
214
+ ```
215
+
216
+ ### 4. Process sequence
217
+
218
+ ```json
219
+ {
220
+ "slides": [{
221
+ "header": { "title": "Our Process" },
222
+ "body": [{
223
+ "primitive": "sequence",
224
+ "orientation": "horizontal",
225
+ "steps": [
226
+ { "label": "Discover", "description": "Understand the problem" },
227
+ { "label": "Design", "description": "Sketch options" },
228
+ { "label": "Ship", "description": "Release to users" }
229
+ ]
230
+ }]
231
+ }]
232
+ }
233
+ ```
234
+
235
+ See `examples/minimal.json` and `examples/full_catalog.json` for complete,
236
+ runnable specs (also used as test fixtures).
237
+
238
+ ## Fonts and overflow validation
239
+
240
+ Overflow checking (`validate`'s layout errors, and the "shrink text on
241
+ overflow" behavior it protects against) reads real glyph advance widths via
242
+ `fonttools` — no rendering required. As of this release, no font is bundled
243
+ into the package yet (`src/compono/fonts/` is a placeholder); validation
244
+ falls back to a system font if one is found (e.g. `arial.ttf` on Windows),
245
+ and is skipped — not faked — with a warning if none is available. A bundled,
246
+ OFL-licensed safe-font list is planned before the first tagged release; this
247
+ section will list it once shipped.
248
+
249
+ ## CLI
250
+
251
+ ```bash
252
+ compono validate spec.json
253
+ compono render spec.json --template fractal -o deck.pptx
254
+ ```
255
+
256
+ Mirrors `validate`/`render_deck` exactly — useful for agent frameworks that
257
+ can only shell out rather than import Python.
258
+
259
+ ## Contributing
260
+
261
+ See `CONTRIBUTING.md` for dev setup, branching, and code style. If you're
262
+ using Claude Code, `.claude/README.md` describes the build-workflow skill,
263
+ review subagent, and commit/format hooks set up for this repo.
@@ -0,0 +1,249 @@
1
+ # compono
2
+
3
+ **Agent-oriented, code-based PPTX generation — "Manim, but for PowerPoint."**
4
+
5
+ compono lets an LLM agent (or a human) describe a slide deck as data —
6
+ headers, bullet text, stats, tables, charts, images, process sequences,
7
+ shapes — and get back a real, editable `.pptx` file. The agent never writes
8
+ raw `x`/`y`/`w`/`h` coordinates: a constraint-based layout resolver computes
9
+ every position from a small set of typed primitives.
10
+
11
+ Every rendered element is a genuine, editable native shape (`p:sp`, `p:pic`,
12
+ `p:graphicFrame`) — never a flattened image or embedded video. Open the
13
+ result in PowerPoint and drag a box around; it's a real object, not a
14
+ picture of one.
15
+
16
+ This file is both the human-facing README and the in-context reference an
17
+ agent uses to call compono correctly — see `skills/compono/SKILL.md` for the
18
+ packaged version of the same content.
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ pip install compono # not yet published — see CHANGELOG.md for status
24
+ ```
25
+
26
+ For local development, see `CONTRIBUTING.md`.
27
+
28
+ ## Quickstart
29
+
30
+ ```python
31
+ from compono import render_deck
32
+
33
+ spec = {
34
+ "slides": [
35
+ {
36
+ "header": {"title": "Q3 Results", "subtitle": "Engineering team"},
37
+ "body": [
38
+ {
39
+ "primitive": "text",
40
+ "mode": "bullets",
41
+ "content": [
42
+ "Shipped the new layout resolver",
43
+ "Cut render time by 40%",
44
+ "Zero overflow bugs in production",
45
+ ],
46
+ "emphasis_indices": [1],
47
+ }
48
+ ],
49
+ }
50
+ ]
51
+ }
52
+
53
+ report = render_deck(spec, "deck.pptx")
54
+ print(report.pptx_path, report.warnings)
55
+ ```
56
+
57
+ Or from the command line:
58
+
59
+ ```bash
60
+ compono validate spec.json
61
+ compono render spec.json -o deck.pptx
62
+ ```
63
+
64
+ ## Core concepts
65
+
66
+ - **One entry point, two verbs.** `render_deck(spec, output_path)` and
67
+ `validate(spec)` are the only two functions you need. `validate` is cheap
68
+ — no pptx write, millisecond-scale — so an agent can iterate on a spec
69
+ before paying render cost.
70
+ - **A spec is plain data.** Either a raw `dict`/JSON (what an agent's
71
+ tool-calling naturally produces) or the typed builder classes
72
+ (`Deck`, `Header`, `Text`, ...) — both serialize to the identical shape.
73
+ There's no divergence between the two paths.
74
+ - **You never write coordinates.** Every primitive claims space in a slide;
75
+ the resolver (a CSS-flexbox-style directional box model) computes real
76
+ EMU positions. `grid` is the one primitive that does true 2D
77
+ row/column math.
78
+ - **Errors are fixes, not diagnoses.** Every validation/render failure is
79
+ `{slide, primitive, field, error, detail, fix}` — see
80
+ [Error shape](#error-shape) below.
81
+ - **render_deck returns a report, not just a file** —
82
+ `{pptx_path, manifest, warnings, actual_layout}` — so an agent can reason
83
+ about what happened without reopening the file.
84
+
85
+ ## API reference
86
+
87
+ ```python
88
+ from compono import (
89
+ render_deck, validate,
90
+ Deck, Slide, Header, Text, Image, Stat, Grid, Table, Sequence, Chart, Shape,
91
+ DeckValidationError,
92
+ )
93
+ ```
94
+
95
+ | Symbol | Signature | Notes |
96
+ |---|---|---|
97
+ | `render_deck` | `render_deck(spec, output_path, *, template=None) -> RenderReport` | Validates, resolves layout, writes a real `.pptx`. Raises `DeckValidationError` on any error — nothing is written on failure. |
98
+ | `validate` | `validate(spec, *, template=None) -> ValidationReport` | Schema + layout + text-overflow checks. No file I/O. Never raises — check `.valid`/`.errors`. |
99
+ | `DeckValidationError` | `exc.errors -> list[dict]` | The one exception type. Carries the structured error list below. |
100
+
101
+ A `Deck` is `{template?: str, slides: [Slide, ...]}`. A `Slide` is
102
+ `{header?: Header, body: [primitive, ...], notes?: str}`. `body` (and
103
+ `grid.items`) accept any primitive, keyed by its `"primitive"` field.
104
+
105
+ ### Error shape
106
+
107
+ ```json
108
+ {
109
+ "slide": 3,
110
+ "primitive": "grid.items[1]",
111
+ "field": "content",
112
+ "error": "overflow",
113
+ "detail": "Text is ~14pt too tall for the box at font size 18pt (6 lines).",
114
+ "fix": "Shorten the text, reduce bullet/line count, or split into two slides."
115
+ }
116
+ ```
117
+
118
+ ## Primitive catalog
119
+
120
+ Every primitive accepts an optional `id` (needed if another primitive
121
+ references it, e.g. a connector) and an optional `notes` (speaker notes).
122
+
123
+ | Primitive | Key fields | Purpose |
124
+ |---|---|---|
125
+ | `header` | `title`, `subtitle?`, `eyebrow?`, `align` | Slide title region. |
126
+ | `text` | `mode` (paragraph/bullets), `content`, `columns?`, `emphasis_indices?` | Prose or bullet list. |
127
+ | `image` | `src?`, `placeholder`, `caption?`, `fit` (cover/contain) | A real picture, or a first-class placeholder — see below. |
128
+ | `stat` | `value`, `label`, `trend?` | A headline number with a label. |
129
+ | `grid` | `items`, `columns`, `direction`, `align`, `justify` | The one primitive with true 2D layout. Items can be any primitive, including nested grids. |
130
+ | `table` | `headers`, `rows`, `emphasis_row?`, `emphasis_col?` | Renders as a real OOXML table (`p:graphicFrame`), not an image. |
131
+ | `sequence` | `steps` (`{label, description?}`), `orientation` | A row/column of connected step boxes — process/timeline diagrams. |
132
+ | `chart` | `chart_type` (bar/line/pie), `categories`, `series` | A real, editable native chart with live data — not a picture of a chart. |
133
+ | `shape` | `kind` (rect/rounded_rect/oval/line/arrow/connector), `fill`, `border`, `connects?`, `text?` | Freeform shape, optionally with text inside, or a connector between two other primitives by `id`. |
134
+
135
+ Every schema field's description is written as an instruction (e.g. "Keep
136
+ under ~60 characters — longer titles will be shrunk by the resolver"), not
137
+ a bare type label — call `Header.model_json_schema()` (or any primitive
138
+ class) to get the full JSON Schema with these descriptions inline.
139
+
140
+ ### Image placeholders
141
+
142
+ Set `"placeholder": true` (with an optional `caption`) instead of `src` when
143
+ you don't have a real image yet. It renders as an intentional design
144
+ element — dashed border, centered caption — and `render_deck`'s
145
+ `RenderReport.manifest` gets one entry per placeholder:
146
+ `{slide, primitive, rect: {x, y, w, h}, caption}`. A later pass (image
147
+ search/generation/human upload) can fill each reserved rect directly from
148
+ the manifest EMU rect — no re-layout needed, and the deck-building agent
149
+ itself never needs image-generation capability.
150
+
151
+ ## Worked examples
152
+
153
+ ### 1. Title slide
154
+
155
+ ```json
156
+ {
157
+ "slides": [
158
+ { "header": { "title": "2026 Roadmap", "subtitle": "Platform team", "eyebrow": "Q1 Kickoff" } }
159
+ ]
160
+ }
161
+ ```
162
+
163
+ ### 2. Two-column comparison with a connector
164
+
165
+ ```json
166
+ {
167
+ "slides": [{
168
+ "header": { "title": "Before vs. After" },
169
+ "body": [
170
+ {
171
+ "primitive": "grid",
172
+ "columns": 2,
173
+ "items": [
174
+ { "id": "before", "primitive": "shape", "kind": "rounded_rect", "fill": "#EF4444",
175
+ "text": { "content": "Manual layout" } },
176
+ { "id": "after", "primitive": "shape", "kind": "rounded_rect", "fill": "#10B981",
177
+ "text": { "content": "Resolver-computed layout" } }
178
+ ]
179
+ },
180
+ { "primitive": "shape", "kind": "connector", "connects": { "from_id": "before", "to_id": "after" } }
181
+ ]
182
+ }]
183
+ }
184
+ ```
185
+
186
+ ### 3. Stat + table + chart dashboard
187
+
188
+ ```json
189
+ {
190
+ "slides": [{
191
+ "header": { "title": "Q3 Metrics" },
192
+ "body": [
193
+ { "primitive": "stat", "value": "42%", "label": "YoY growth", "trend": "+12% vs Q2" },
194
+ { "primitive": "table", "headers": ["Quarter", "Revenue"], "rows": [["Q1", "10"], ["Q2", "14"]] },
195
+ { "primitive": "chart", "chart_type": "bar", "categories": ["Q1", "Q2"],
196
+ "series": [{ "name": "Revenue", "values": [10, 14] }] }
197
+ ]
198
+ }]
199
+ }
200
+ ```
201
+
202
+ ### 4. Process sequence
203
+
204
+ ```json
205
+ {
206
+ "slides": [{
207
+ "header": { "title": "Our Process" },
208
+ "body": [{
209
+ "primitive": "sequence",
210
+ "orientation": "horizontal",
211
+ "steps": [
212
+ { "label": "Discover", "description": "Understand the problem" },
213
+ { "label": "Design", "description": "Sketch options" },
214
+ { "label": "Ship", "description": "Release to users" }
215
+ ]
216
+ }]
217
+ }]
218
+ }
219
+ ```
220
+
221
+ See `examples/minimal.json` and `examples/full_catalog.json` for complete,
222
+ runnable specs (also used as test fixtures).
223
+
224
+ ## Fonts and overflow validation
225
+
226
+ Overflow checking (`validate`'s layout errors, and the "shrink text on
227
+ overflow" behavior it protects against) reads real glyph advance widths via
228
+ `fonttools` — no rendering required. As of this release, no font is bundled
229
+ into the package yet (`src/compono/fonts/` is a placeholder); validation
230
+ falls back to a system font if one is found (e.g. `arial.ttf` on Windows),
231
+ and is skipped — not faked — with a warning if none is available. A bundled,
232
+ OFL-licensed safe-font list is planned before the first tagged release; this
233
+ section will list it once shipped.
234
+
235
+ ## CLI
236
+
237
+ ```bash
238
+ compono validate spec.json
239
+ compono render spec.json --template fractal -o deck.pptx
240
+ ```
241
+
242
+ Mirrors `validate`/`render_deck` exactly — useful for agent frameworks that
243
+ can only shell out rather than import Python.
244
+
245
+ ## Contributing
246
+
247
+ See `CONTRIBUTING.md` for dev setup, branching, and code style. If you're
248
+ using Claude Code, `.claude/README.md` describes the build-workflow skill,
249
+ review subagent, and commit/format hooks set up for this repo.
@@ -0,0 +1,31 @@
1
+ [project]
2
+ name = "compono"
3
+ version = "0.1.0"
4
+ description = "Agent-oriented, code-based PPTX generation library — Manim, but for PowerPoint."
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ authors = [
8
+ { name = "Shaik-Hamzah123", email = "hamzah.shaik2003@gmail.com" }
9
+ ]
10
+ requires-python = ">=3.13"
11
+ dependencies = [
12
+ "fonttools>=4.65.0",
13
+ "pydantic>=2.13.5",
14
+ "python-pptx>=1.0.2",
15
+ "pyyaml>=6.0.3",
16
+ ]
17
+
18
+ [project.scripts]
19
+ compono = "compono.cli:main"
20
+
21
+ [build-system]
22
+ requires = ["uv_build>=0.11.17,<0.12.0"]
23
+ build-backend = "uv_build"
24
+
25
+ [dependency-groups]
26
+ dev = [
27
+ "mypy>=2.3.1",
28
+ "pytest>=9.1.1",
29
+ "ruff>=0.16.7",
30
+ "types-pyyaml>=6.0.12.20260906",
31
+ ]
@@ -0,0 +1,45 @@
1
+ """compono — agent-oriented, code-based PPTX generation library.
2
+
3
+ Public exports ONLY (COMPONO_PLAN.md section 10) — resolver/validator/template
4
+ loader stay internal, reached only through render_deck/validate.
5
+ """
6
+
7
+ from compono.render import (
8
+ DeckValidationError,
9
+ RenderReport,
10
+ ValidationReport,
11
+ render_deck,
12
+ validate,
13
+ )
14
+ from compono.schema import (
15
+ Chart,
16
+ Deck,
17
+ Grid,
18
+ Header,
19
+ Image,
20
+ Sequence,
21
+ Shape,
22
+ Slide,
23
+ Stat,
24
+ Table,
25
+ Text,
26
+ )
27
+
28
+ __all__ = [
29
+ "Chart",
30
+ "Deck",
31
+ "DeckValidationError",
32
+ "Grid",
33
+ "Header",
34
+ "Image",
35
+ "RenderReport",
36
+ "Sequence",
37
+ "Shape",
38
+ "Slide",
39
+ "Stat",
40
+ "Table",
41
+ "Text",
42
+ "ValidationReport",
43
+ "render_deck",
44
+ "validate",
45
+ ]
@@ -0,0 +1,70 @@
1
+ """Console-script entry point mirroring the render_deck/validate verbs.
2
+
3
+ compono validate spec.json
4
+ compono render spec.json --template fractal -o deck.pptx
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import argparse
10
+ import json
11
+ import sys
12
+ from pathlib import Path
13
+
14
+ from compono.render import DeckValidationError, render_deck, validate
15
+
16
+
17
+ def _load_spec(path: str) -> dict:
18
+ return json.loads(Path(path).read_text(encoding="utf-8"))
19
+
20
+
21
+ def main(argv: list[str] | None = None) -> int:
22
+ parser = argparse.ArgumentParser(prog="compono")
23
+ subparsers = parser.add_subparsers(dest="command", required=True)
24
+
25
+ validate_parser = subparsers.add_parser("validate", help="Validate a deck spec without rendering.")
26
+ validate_parser.add_argument("spec", help="Path to a JSON deck spec.")
27
+
28
+ render_parser = subparsers.add_parser("render", help="Render a deck spec to a .pptx file.")
29
+ render_parser.add_argument("spec", help="Path to a JSON deck spec.")
30
+ render_parser.add_argument("-o", "--output", default="deck.pptx", help="Output .pptx path.")
31
+ render_parser.add_argument(
32
+ "--template", default=None, help="Template name (reserved; the default template is used for now)."
33
+ )
34
+
35
+ args = parser.parse_args(argv)
36
+
37
+ if args.command == "validate":
38
+ spec = _load_spec(args.spec)
39
+ validation_report = validate(spec)
40
+ print(
41
+ json.dumps(
42
+ {
43
+ "valid": validation_report.valid,
44
+ "errors": validation_report.errors,
45
+ "warnings": validation_report.warnings,
46
+ },
47
+ indent=2,
48
+ )
49
+ )
50
+ return 0 if validation_report.valid else 1
51
+
52
+ if args.command == "render":
53
+ spec = _load_spec(args.spec)
54
+ try:
55
+ render_report = render_deck(spec, args.output)
56
+ except DeckValidationError as exc:
57
+ print(json.dumps({"valid": False, "errors": exc.errors}, indent=2), file=sys.stderr)
58
+ return 1
59
+ print(
60
+ json.dumps(
61
+ {"pptx_path": str(render_report.pptx_path), "warnings": render_report.warnings}, indent=2
62
+ )
63
+ )
64
+ return 0
65
+
66
+ return 1
67
+
68
+
69
+ if __name__ == "__main__":
70
+ raise SystemExit(main())
File without changes
@@ -0,0 +1,5 @@
1
+ """Typed builder classes (human path). Pure sugar over the pydantic schema in schema.py.
2
+
3
+ Serializes to the identical dict shape the agent path (raw JSON/dict) uses —
4
+ see COMPONO_PLAN.md section 9. Populated starting Step 1.
5
+ """
File without changes