@uniweb/unipress 0.2.2

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/CHANGELOG.md ADDED
@@ -0,0 +1,137 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0
4
+
5
+ The credibility-shifting release. Two production-shaped foundations
6
+ (`@uniweb/book`, `@uniweb/data`), five templates (`book`, `monograph`,
7
+ `report`, `data-report`, `directory`), and a vocabulary cleanup that
8
+ separates create-time templates from runtime foundations.
9
+
10
+ ### Added
11
+
12
+ - **`@uniweb/book`** foundation. Long-form prose with chapters; outputs
13
+ Typst/PDF, Paged.js HTML, EPUB. Default section type `Chapter` plus
14
+ `Cover`, `BackCover`, `BackMatter`, `Contents`. Inlines parameterised
15
+ Typst defaults (trim, typography, structure, localized labels) and a
16
+ CSS Paged Media stylesheet.
17
+ - **`@uniweb/data`** foundation. Aggregates structured records and
18
+ emits Excel workbooks + Word reports. Eight section types
19
+ (`Cover`, `Members`, `Publications*` ×4, `Funding`, `Supervisions`)
20
+ with Loom-driven aggregate stats and a queryable filter surface.
21
+ - **Five templates** under `documents/`:
22
+ - `book` — trade-6x9 prose (3 chapters).
23
+ - `monograph` — royal-octavo, EB Garamond, `tocDepth: 3`.
24
+ - `report` — trade-7x10, block paragraphs, code-margin relief.
25
+ - `data-report` — migrated from the v0.1 `academic-metrics`
26
+ placeholder; aggregate metrics across sample naturalists.
27
+ - `directory` — flat records listing with filterable surface.
28
+ - **Per-template docs** at `docs/templates/<name>.md` covering the
29
+ `document.yml` fields that matter, common customizations, and
30
+ links to the foundation README.
31
+ - **Registry-ref resolver** in `foundation-loader.js`. The fifth ref
32
+ form `@<namespace>/<name>@<version>` constructs a URL from
33
+ `UNIWEB_REGISTRY_URL` (or the production default at
34
+ `site-router.uniweb-edge.workers.dev`) and fetches via the existing
35
+ cache. Catalog entries pin registry refs; scaffolded `document.yml`
36
+ files inherit them.
37
+
38
+ ### Changed
39
+
40
+ - **Vocabulary**: `unipress create` now takes `--template <id>`
41
+ instead of `--foundation <id>`, and `list-foundations` is renamed
42
+ to `list-templates`. Catalog ids are templates — starter content
43
+ pinning a foundation. Runtime concepts keep the foundation name
44
+ (`compile --foundation`, `document.yml`'s `foundation:`).
45
+ - **Catalog entry shape**: `{ source: { url } }` →
46
+ `{ foundation: { ref, source: { url } } }`. The new `foundation.ref`
47
+ is the registry ref scaffolded `document.yml` files pin; the
48
+ `foundation.source.url` is the human-readable "where this lives"
49
+ pointer shown in `list-templates` output.
50
+ - **Repo layout**: `framework/unipress/` is now a nested pnpm
51
+ workspace. Foundations developed for unipress live under
52
+ `foundations/<name>/`; documents (foundation-dev test harnesses
53
+ AND bundled template starter content) live under `documents/<name>/`.
54
+ The `scripts/generate-templates-data.js` generator reads from
55
+ `documents/` and rewrites path-ref `foundation:` values to registry
56
+ refs at bundle time so the on-disk file stays dev-friendly while
57
+ the bundled file is end-user-friendly.
58
+
59
+ ### Removed
60
+
61
+ - `--foundation` flag on `create`. Errors with a pointer to
62
+ `--template` (no deprecation alias — pre-1.0).
63
+ - `list-foundations` command. Errors with a pointer to `list-templates`.
64
+ - `templates/` directory; `package.json`'s `files:` array now ships
65
+ `documents/`.
66
+
67
+ ### Caveat
68
+
69
+ Catalog entries currently point at the **local registry**
70
+ (`http://localhost:4001/registry/packages/<ns>/<name>/<ver>/foundation.js`).
71
+ Scaffolded documents will fail to fetch the foundation unless the
72
+ foundations are published locally via `uniweb publish --local` against
73
+ a running unicloud, OR the user passes `--foundation <path>` explicitly.
74
+ A follow-up release switches the catalog URLs to the production
75
+ registry once `@uniweb/book` and `@uniweb/data` publish there.
76
+
77
+ ## 0.1.0 (unreleased)
78
+
79
+ First working release, published as `@uniweb/unipress` after the
80
+ unscoped `unipress` name was abandoned (npm Levenshtein-policy
81
+ conflict with `unirest`). The CLI binary is still `unipress`; only the
82
+ package specifier is scoped. All functionality below is in the working
83
+ tree and exercised end-to-end against the v0.1 reference foundation
84
+ (198-page PDF via Typst 0.14.2).
85
+
86
+ ### Added
87
+
88
+ - `unipress compile <dir>` — compile a content directory into a
89
+ document. Calls `foundation.compileDocument(website, { format,
90
+ foundation, ...hostHints })` and sinks the resulting Blob.
91
+ - Format support: whatever the foundation declares in its `outputs:`
92
+ map. Today that's PDF / Typst source zip / Paged.js HTML / EPUB via
93
+ `@proximify/press-book`; other formats land when their foundations do.
94
+ - Typst binary manager: pinned to `0.14.2`, SHA-256-verified, cached
95
+ under `$UNIPRESS_CACHE_DIR` or the platform default (XDG /
96
+ `~/Library/Caches/unipress` / `~/.cache/unipress`). Override with
97
+ `--typst-binary <path>`.
98
+ - `unipress.config.js` + `--config <path>`. Precedence: CLI > config >
99
+ `document.yml` > defaults. Fields: `format`, `foundation`, `out`,
100
+ `typst.binary`, `typst.version`. Relative paths resolve against the
101
+ config file's directory.
102
+ - `unipress inspect <dir>` — JSON dump of the resolved Website graph,
103
+ with filtering knobs (`--full`, `--summary`, `--page <route>`,
104
+ `--depth <n>`, `--foundation <ref>`, `--no-orchestrate`).
105
+ - Foundation resolver: npm package name (walks `node_modules/`, picks
106
+ `exports['./dist']`) or local path. URL-based resolution is planned.
107
+ - Named error catalog (`ContentDirectoryError`, `DocumentYmlError`,
108
+ `ConfigValidationError`, `FoundationResolutionError`, `CompileError`,
109
+ `OutputWriteError`, `TypstBinaryError`, plus three reserved for
110
+ later milestones). `UnipressError.format()` produces structured
111
+ multi-line output. Top-level handler splits exit codes: `1` for
112
+ user-addressable errors, `2` for internal bugs.
113
+ - `--verbose` flag — step-by-step progress to stderr + stack traces on
114
+ errors.
115
+ - `--keep-temp` flag — preserves the typst temp directory on compile
116
+ failure so the generated source bundle can be inspected.
117
+
118
+ ### Framework-side changes that shipped alongside
119
+
120
+ - [`@uniweb/press`] `compileDocument(websiteOrTree, options)` — the
121
+ high-level compile entry point. Tree mode passes through to
122
+ `compileSubtree`; website mode reads `foundation.outputs[format]`,
123
+ assembles adapter options, gathers blocks, dispatches.
124
+ - [`@uniweb/build`] Host-shareable re-export extended — the generated
125
+ entry now re-exports both `compileSubtree` and `compileDocument`
126
+ when the foundation depends on `@uniweb/press`.
127
+ - [docs] New "Document Outputs" section in `foundation-config.md`
128
+ covering the `outputs: { <format>: { getOptions, via?, extension? } }`
129
+ contract.
130
+
131
+ (0.1.0 was never tagged; its content shipped under the 0.0.1 working
132
+ tree and was superseded by 0.2.0 directly.)
133
+
134
+ ## 0.0.1
135
+
136
+ - Name-reservation release. CLI prints help and version; no commands
137
+ are implemented yet.
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,213 @@
1
+ # unipress
2
+
3
+ **Compile a directory of markdown into a document — typeset PDF, EPUB, Word, Excel, Paged.js HTML, Typst source — using a foundation that knows the conventions of the kind of document you're writing.**
4
+
5
+ ```bash
6
+ unipress create my-book
7
+ unipress compile my-book
8
+ ```
9
+
10
+ Two commands. The first scaffolds a starter project; the second produces the file.
11
+
12
+ ## What it makes
13
+
14
+ | Format | What it's for |
15
+ |---|---|
16
+ | **PDF** | The finished, typeset document. Real typography, real pagination, ready to print or share. Built on [Typst](https://typst.app), the modern typesetting system. |
17
+ | **EPUB** | The format Kindles and other ebook readers use. |
18
+ | **Word (`.docx`)** | When a journal, committee, or collaborator needs a Word file. |
19
+ | **Excel (`.xlsx`)** | When the document is structured data — a directory, a dataset, a registry — rather than prose. |
20
+ | **Paged.js HTML** | Browser-paginated HTML you can print to PDF or post on the web. |
21
+ | **Typst source** | The `.typ` files unipress feeds the compiler. Useful if you want to take the typesetting further yourself, or hand off to a designer. |
22
+
23
+ Equations work in the standard LaTeX style — `$E = mc^2$` for inline, `$$...$$` for displayed. Tables, lists, footnotes, code blocks, and images all behave the way you'd expect from markdown.
24
+
25
+ ## Two ways to use it
26
+
27
+ **For authors.** unipress is a tool. Pick a template, write markdown, compile. The template knows the conventions for its kind of document — typography, structure, the bits that make a book look like a book and a directory look like a directory. You handle the content; the template handles everything else.
28
+
29
+ **For developers.** unipress is an engine. A *foundation* is a component system that declares what section types exist (`type: Chapter`, `type: Bibliography`), where data comes from (`data:` declarations), and what output formats it can emit (`outputs: { docx, xlsx, pdf, custom-format }`). Authors write markdown against your vocabulary; unipress runs your foundation against their content. Same content directory, multiple outputs your foundation chooses to support — typeset book, accessible EPUB, regulatory report, structured data feed. The same foundation can also drive a [Uniweb](https://uniweb.io) website, so the work is never single-purpose.
30
+
31
+ Foundations consume [`@uniweb/press`](https://github.com/uniweb/press) for the bytes-emitting work. Press is the output layer (Word, Excel, Typst today; more formats shipping); the foundation is your vocabulary.
32
+
33
+ ## Install
34
+
35
+ **Standalone binary (recommended for most users).** No Node, no npm. Download the asset for your platform from [the releases page](https://github.com/uniweb/unipress/releases), make it executable, and put it somewhere on your `PATH` — `/usr/local/bin/unipress` is a common choice on macOS and Linux. Then you can run `unipress` from any directory.
36
+
37
+ **npm.** If you already have Node:
38
+
39
+ ```bash
40
+ npm i -g @uniweb/unipress
41
+ ```
42
+
43
+ ## Pick a template
44
+
45
+ Five built-in templates ship with the binary. Run `unipress list-templates` for the picker.
46
+
47
+ | Template | Foundation | Outputs | Use case |
48
+ |---|---|---|---|
49
+ | `book` | `@uniweb/book` | pdf, typst, pagedjs, epub | Trade book, long-form prose |
50
+ | `monograph` | `@uniweb/book` | pdf, typst, pagedjs, epub | Scholarly monograph (royal-octavo, classical typography) |
51
+ | `report` | `@uniweb/book` | pdf, typst, pagedjs, epub | Technical report (trade-7x10, block paragraphs) |
52
+ | `data-report` | `@uniweb/data` | xlsx, docx | Aggregate metrics across structured records |
53
+ | `directory` | `@uniweb/data` | xlsx, docx | Flat records listing with a filterable surface |
54
+
55
+ Per-template guides: [`docs/templates/`](./docs/templates/).
56
+
57
+ More templates land as more foundations ship — `cv`, `resume`, `paper`, `thesis` are on the roadmap for upcoming releases.
58
+
59
+ ## Write your first document
60
+
61
+ ```bash
62
+ unipress create my-book --template book --title "My Book" --author "Your Name"
63
+ cd my-book
64
+ ```
65
+
66
+ The result is a content-only directory — markdown pages, a `document.yml`, optional `theme.yml` and `assets/`. **No `package.json`, no `node_modules`.** Edit the markdown — that's your content. Numbered filenames (`01-intro.md`, `02-chapter-one.md`) keep chapter order predictable.
67
+
68
+ When you're ready to produce the document:
69
+
70
+ ```bash
71
+ unipress compile . --format pdf
72
+ ```
73
+
74
+ Or any of the formats the foundation declares (`--format epub`, `--format pagedjs`). Write, compile, look at the result, revise, compile again — that's the loop.
75
+
76
+ The first PDF run downloads Typst 0.14.2 to `~/Library/Caches/unipress/typst/0.14.2/` (or the XDG cache dir on Linux). Subsequent runs reuse the cached binary.
77
+
78
+ ## Custom foundations
79
+
80
+ Any foundation that declares an `outputs: { … }` map on its default export can drive unipress. Point `document.yml`'s `foundation:` at:
81
+
82
+ - a registry ref: `@<namespace>/<name>@<version>` — fetched from the Uniweb registry, cached locally,
83
+ - a URL: `https://…/foundation.js`,
84
+ - a local filesystem path: `./foundation`, `/abs/path`, etc.
85
+
86
+ The local-path form is the everyday dev loop — point unipress at a foundation directory you're iterating on, no publish step needed:
87
+
88
+ ```bash
89
+ unipress compile my-doc --foundation ../my-foundation
90
+ ```
91
+
92
+ For the foundation contract — the `outputs:` map, the `getOptions(website, hostHints)` function, what bytes a foundation can emit — see the [foundation authors' guide](https://github.com/uniweb/docs/blob/main/reference/foundation-config.md#document-outputs). Foundations are distributed via the [Uniweb registry](https://uniweb.io), not npm.
93
+
94
+ ---
95
+
96
+ Below this point is reference material — useful when you want to do something beyond the basics, or when something doesn't behave as expected.
97
+
98
+ ## CLI reference
99
+
100
+ ```text
101
+ unipress compile <dir> [options]
102
+ --format <fmt> Output format (pdf | typst | docx | xlsx | pagedjs | epub).
103
+ Overrides the format: field in document.yml.
104
+ --foundation <ref> Override document.yml's foundation. Accepts:
105
+ - registry ref: @<namespace>/<name>@<version>
106
+ - URL: https://…/foundation.js
107
+ - path: ./foundation, /abs/path, …
108
+ --out <path> Output file (default: ./<dir-basename>.<ext>).
109
+ --config <path> Explicit config file (default: <dir>/unipress.config.js).
110
+ --typst-binary <p> Path to a typst binary (skips the managed download).
111
+ --keep-temp On typst-compile failure, keep the temp dir for inspection.
112
+ --verbose Per-step progress to stderr + stack traces on errors.
113
+
114
+ unipress create <dir> [options]
115
+ --template <id> Template to scaffold (interactive picker if omitted).
116
+ Run `unipress list-templates` to see available ids.
117
+ --title <str> Document title (prompts if omitted).
118
+ --author <str> Document author (prompts if omitted).
119
+ --force Overwrite non-empty <dir>.
120
+ --yes Skip prompts (requires --template).
121
+
122
+ unipress list-templates
123
+ List the templates available, one per line, with description, outputs,
124
+ the foundation each pins, and the source URL where the foundation lives.
125
+
126
+ unipress inspect <dir> [options]
127
+ Dump the parsed content as JSON (debugging aid).
128
+ --full Include web-only fields (assets, icons, etc.).
129
+ --summary Replace pages[] with route strings only.
130
+ --page <route> Keep only the page matching <route>.
131
+ --depth <n> Truncate nested values beyond depth n.
132
+ --foundation <ref> Override document.yml's foundation.
133
+ --no-orchestrate Skip running the foundation; show only the parsed content.
134
+
135
+ unipress --help
136
+ unipress --version
137
+ ```
138
+
139
+ Exit codes: `0` success, `1` user-addressable error, `2` internal error (re-run with `--verbose` for a stack trace).
140
+
141
+ ## Configuration
142
+
143
+ ### `document.yml`
144
+
145
+ The content-directory-level config. Fields unipress reads:
146
+
147
+ | Field | Purpose |
148
+ |---|---|
149
+ | `name` | Document name (used as a title fallback). |
150
+ | `foundation` | Registry ref (`@ns/name@ver`), URL, or local path to the foundation. |
151
+ | `format` | Default output format. Overridable by CLI `--format` or `unipress.config.js`. |
152
+ | `pages:` | Reading order (same semantics as a Uniweb site's `site.yml`). |
153
+ | `book:`, `report:`, `collections:` … | Foundation-specific config blocks. The foundation's `getOptions` reads these. |
154
+
155
+ `site.yml` is also accepted as a fallback for compatibility with existing Uniweb site directories.
156
+
157
+ ### `unipress.config.js`
158
+
159
+ Optional ESM file for things awkward in YAML — imports, computed values, format-specific overrides. Auto-discovered at `<dir>/unipress.config.js` or explicit via `--config <path>`.
160
+
161
+ ```js
162
+ import { defineUnipressConfig } from '@uniweb/unipress'
163
+
164
+ export default defineUnipressConfig({
165
+ out: './dist/my-book.pdf', // overrides --out default
166
+ format: 'pdf', // overrides document.yml format
167
+
168
+ typst: {
169
+ version: '0.14.2', // override the pinned Typst version
170
+ binary: '/usr/local/bin/typst', // skip the managed download
171
+ },
172
+ })
173
+ ```
174
+
175
+ Plain `export default { … }` works equally well; `defineUnipressConfig` is an identity wrapper for editor autocomplete.
176
+
177
+ Relative paths in the config (`out`, `foundation`, `typst.binary`) resolve against the **config file's directory** — matching Vite / Astro convention.
178
+
179
+ ### Precedence chain
180
+
181
+ ```
182
+ CLI flags > unipress.config.js > document.yml > defaults
183
+ ```
184
+
185
+ Applied per-field.
186
+
187
+ ## Typst binary
188
+
189
+ `--format pdf` requires a Typst binary. unipress pins `0.14.2` and manages the download:
190
+
191
+ - **Cache location:** `$UNIPRESS_CACHE_DIR` > `$XDG_CACHE_HOME/unipress` > `~/Library/Caches/unipress` (macOS) > `~/.cache/unipress` (fallback). Binary path: `<cache>/typst/<version>/typst`.
192
+ - **Override:** pass `--typst-binary <path>` or set `typst.binary` in `unipress.config.js`.
193
+ - **Checksum verified:** each download is SHA-256-checked against the digest pinned in `src/typst/versions.js`.
194
+
195
+ ## Where things stand
196
+
197
+ unipress is **pre-1.0**. The CLI is stable enough to write real documents with — the `book` template, in particular, is well-tested. Future versions may change small things, but `document.yml` files and project folders from today should keep working: scaffolded projects pin a specific foundation version, and registry artifacts are immutable.
198
+
199
+ **Heads-up for v0.2:** the bundled catalog points at a local registry (`http://localhost:4001/...`) until the foundations publish to the production Uniweb registry. To compile against a bundled template today, either pass `--foundation <path>` pointing at a built foundation directory, or run a local foundation registry (publish a built foundation with `uniweb publish --local` and serve `.unicloud/registry/` on port 4001). A follow-up release switches the catalog to production URLs once `@uniweb/book` and `@uniweb/data` ship there.
200
+
201
+ ## Troubleshooting
202
+
203
+ See [`docs/troubleshooting.md`](./docs/troubleshooting.md) for common errors and fixes — every named error class maps to a cause and a concrete next step.
204
+
205
+ ## See also
206
+
207
+ - [`@uniweb/press`](https://github.com/uniweb/press) — the output layer foundations consume to produce Word/Excel/Typst/EPUB. Foundation authors interact with it directly.
208
+ - [`@uniweb/build`](https://github.com/uniweb/build) — the framework's content-collection pipeline. unipress consumes the sharp-free `/content` entry.
209
+ - [Uniweb](https://uniweb.io) — the larger framework. Foundations originate here; unipress brings them to the command line.
210
+
211
+ ## License
212
+
213
+ Apache-2.0 — see [LICENSE](./LICENSE).
package/RELEASING.md ADDED
@@ -0,0 +1,101 @@
1
+ # Releasing unipress
2
+
3
+ Notes for cutting a release tag (`unipress@<version>`). The release workflow at `.github/workflows/release.yml` watches for tag pushes matching that pattern, builds three binaries (darwin-arm64, linux-x64, windows-x64), and creates a GitHub Release with the binaries and SHA-256 sidecars attached.
4
+
5
+ This file mostly exists to flag one thing the release workflow currently can't handle on its own.
6
+
7
+ ---
8
+
9
+ ## The CI install tension
10
+
11
+ unipress's runtime depends on five `@uniweb/*` framework packages (`@uniweb/build`, `@uniweb/content-reader`, `@uniweb/core`, `@uniweb/runtime`, `@uniweb/semantic-parser`). The CLI is developed inside a larger monorepo where these are sibling packages and resolve via `workspace:*`. That works for local dev — pnpm symlinks the local sources directly — but the release workflow checks out only this repo, with no monorepo around it.
12
+
13
+ Two strategies have been tried, and each has a failure mode:
14
+
15
+ - **`^X.Y.Z` (npm version specs).** Lets CI install standalone from npm. Failure mode: when framework changes ship in unpublished workspace versions, dev machines pnpm-resolve to the npm-published copy instead of the local sibling — meaning `pnpm install` from inside the monorepo silently picks up an older framework. This bit us once; the developer-side breakage is silent and hard to spot.
16
+
17
+ - **`workspace:*` (current).** Dev machines always get the local siblings. Failure mode: CI's `pnpm install --ignore-workspace --no-frozen-lockfile` has no way to resolve `workspace:*` outside a workspace — it will error.
18
+
19
+ Both strategies are correct for one audience and broken for the other. The current state is `workspace:*`, which means **the next release tag will fail at the CI install step until one of the two fixes below lands.**
20
+
21
+ ## Two ways out
22
+
23
+ ### (a) Publish all `@uniweb/*` framework packages to npm at the release version, then flip the specs back to npm ranges at release time
24
+
25
+ The `pnpm framework:publish:*` shortcuts in the outer monorepo handle the framework publish. Workflow:
26
+
27
+ 1. From the outer monorepo, bump + publish all framework packages: `pnpm framework:publish:patch` (or `:minor`).
28
+ 2. Wait for the publish to settle on npm.
29
+ 3. In the unipress repo, change the five `@uniweb/*` deps in `package.json` from `workspace:*` back to `^<published-version>` matching what just shipped.
30
+ 4. Commit, tag `unipress@<version>`, push.
31
+ 5. After the release CI succeeds and the binary is out, switch the deps back to `workspace:*` so dev resolution stays correct.
32
+
33
+ Pros: keeps the CI workflow simple — `pnpm install --ignore-workspace --no-frozen-lockfile` continues to work standalone. The release artifact is reproducible from npm with no monorepo context.
34
+
35
+ Cons: requires a framework publish before every unipress release. Adds a step. The flip-back-to-`workspace:*` after release is easy to forget; if you skip it, the next dev `pnpm install` quietly downgrades the framework deps to the npm-published versions. Worth automating the flip with a script if this becomes the standard path.
36
+
37
+ ### (b) Build the unipress binary inside the outer monorepo's CI
38
+
39
+ Add a release workflow at the **outer monorepo** that:
40
+
41
+ 1. Watches for tag pushes matching `unipress@*`.
42
+ 2. Checks out the outer monorepo (which has the workspace + all `@uniweb/*` siblings cloned via `pnpm clone`).
43
+ 3. Runs `pnpm install` at the outer root (resolves `workspace:*` correctly).
44
+ 4. Runs `node scripts/build-binaries.js` from inside `framework/unipress/`.
45
+ 5. Uploads the resulting binaries to a GitHub Release in the **unipress** repo (cross-repo release via `gh release` with a PAT).
46
+
47
+ Pros: matches the dev environment exactly — workspace:* always resolves the same way locally and in CI. No extra publish step. No flip-back dance.
48
+
49
+ Cons: more workflow complexity. Cross-repo release upload requires a PAT (the workflow's default `GITHUB_TOKEN` is scoped to its own repo). The outer monorepo is private, so the workflow runs there and can't be inspected by anyone outside the org — fine for our purposes but worth noting if unipress ever gets external contributors who want to understand how releases are produced.
50
+
51
+ ## Recommendation
52
+
53
+ **Go with (a) for v0.x releases. Move to (b) once unipress's release cadence outpaces the framework's**, or once the outer monorepo's CI matures enough that adding a cross-repo build step is cheap.
54
+
55
+ Why (a) first:
56
+
57
+ - The framework already publishes to npm on its own cadence. Tagging unipress *after* a framework publish settles is a normal sequencing — every framework feature unipress depends on is on npm anyway by the time a release ships.
58
+ - The flip-back-to-`workspace:*` step is the only friction, and it's a one-line change. Easy to script.
59
+ - (b) is strictly more invasive and ties the unipress release pipeline to the outer monorepo's existence — a coupling worth deferring.
60
+
61
+ When (b) starts to make sense:
62
+
63
+ - If unipress needs to release patches against unpublished framework changes (rare, but possible).
64
+ - If the framework publish cadence becomes the bottleneck on shipping unipress fixes.
65
+ - If cross-repo release infrastructure is already in place for other reasons (e.g., other tools in `framework/` shipping binaries).
66
+
67
+ ## Concrete checklist for the next release
68
+
69
+ Until (b) lands, every release goes through this:
70
+
71
+ ```bash
72
+ # 1. From the outer monorepo: bump + publish framework
73
+ pnpm framework:publish:patch # or :minor
74
+
75
+ # 2. Note the new versions: check `framework/<pkg>/package.json` for each.
76
+
77
+ # 3. In framework/unipress/, edit package.json:
78
+ # - "@uniweb/build": "workspace:*" → "^<new-version>"
79
+ # - (repeat for content-reader, core, runtime, semantic-parser)
80
+
81
+ # 4. Bump unipress version + update CHANGELOG (this file's git history
82
+ # should make the pattern obvious).
83
+
84
+ # 5. Commit + tag + push:
85
+ git add package.json CHANGELOG.md
86
+ git commit -m "release: <version>"
87
+ git tag -a unipress@<version> -m "..."
88
+ git push origin main
89
+ git push origin unipress@<version>
90
+
91
+ # 6. Wait for the release workflow. Confirm artifacts uploaded.
92
+ # The release is created as a draft — review and publish it via
93
+ # `gh release edit unipress@<version> --draft=false`.
94
+
95
+ # 7. Flip framework deps back to workspace:* so dev resolution stays
96
+ # correct against unpublished framework changes:
97
+ git revert <step-3-commit> # or hand-edit + commit
98
+ git push origin main
99
+ ```
100
+
101
+ Step 7 is the easy-to-forget one. If a dev pulls and runs `pnpm install` while the package.json still has the npm specs from step 3, they'll silently get the npm-published framework copies — which means any unpublished framework features won't be available locally. Don't skip step 7.