@open-press/cli 0.7.1 → 1.0.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.
Files changed (234) hide show
  1. package/README.md +29 -13
  2. package/dist/cli.js +44 -195
  3. package/package.json +4 -5
  4. package/template/core/AGENTS.md +18 -14
  5. package/template/core/CHANGELOG.md +57 -9
  6. package/template/core/README.md +6 -3
  7. package/template/core/engine/cli.mjs +8 -8
  8. package/template/core/engine/commands/_shared.mjs +37 -15
  9. package/template/core/engine/commands/dev.mjs +2 -2
  10. package/template/core/engine/commands/image.mjs +29 -0
  11. package/template/core/engine/commands/skills-sync.mjs +71 -0
  12. package/template/core/engine/commands/typecheck.mjs +63 -1
  13. package/template/core/engine/commands/upgrade.mjs +3 -3
  14. package/template/core/engine/document-export.mjs +1 -1
  15. package/template/core/engine/output/chrome-pdf.mjs +110 -3
  16. package/template/core/engine/output/static-server.mjs +87 -9
  17. package/template/core/engine/react/comment-endpoint.mjs +13 -39
  18. package/template/core/engine/react/comment-marker.mjs +43 -19
  19. package/template/core/engine/react/document-entry.mjs +46 -28
  20. package/template/core/engine/react/document-export.mjs +328 -164
  21. package/template/core/engine/react/http-json.mjs +24 -0
  22. package/template/core/engine/react/mdx-compile.mjs +126 -3
  23. package/template/core/engine/react/measurement-css.mjs +114 -1
  24. package/template/core/engine/react/object-entities.mjs +204 -0
  25. package/template/core/engine/react/pagination/allocator.mjs +48 -3
  26. package/template/core/engine/react/pagination.mjs +1 -1
  27. package/template/core/engine/react/pipeline/allocate.mjs +41 -72
  28. package/template/core/engine/react/pipeline/frame-measurement.mjs +6 -0
  29. package/template/core/engine/react/press-tree-inspection.mjs +172 -0
  30. package/template/core/engine/react/project-asset-endpoint.mjs +6 -24
  31. package/template/core/engine/react/source-edit-endpoint.d.mts +10 -0
  32. package/template/core/engine/react/source-edit-endpoint.mjs +75 -0
  33. package/template/core/engine/react/sources/mdx-resolver.mjs +13 -15
  34. package/template/core/engine/react/style-discovery.mjs +23 -8
  35. package/template/core/engine/runtime/config.d.mts +8 -0
  36. package/template/core/engine/runtime/config.mjs +57 -60
  37. package/template/core/engine/runtime/file-utils.mjs +9 -1
  38. package/template/core/engine/runtime/file-walk.mjs +22 -0
  39. package/template/core/engine/runtime/inspection.mjs +1 -20
  40. package/template/core/engine/runtime/page-geometry.mjs +131 -0
  41. package/template/core/engine/runtime/path-utils.mjs +20 -0
  42. package/template/core/engine/runtime/source-text-tools.d.mts +102 -0
  43. package/template/core/engine/runtime/source-text-tools.mjs +551 -16
  44. package/template/core/engine/runtime/source-workspace.mjs +16 -34
  45. package/template/core/engine/runtime/validation.mjs +19 -10
  46. package/template/core/openpress.config.mjs +3 -7
  47. package/template/core/package.json +3 -5
  48. package/template/core/src/main.tsx +2 -2
  49. package/template/core/src/openpress/app/OpenPressApp.tsx +296 -0
  50. package/template/core/src/openpress/{renderer.tsx → app/OpenPressRuntime.tsx} +20 -9
  51. package/template/core/src/openpress/app/WorkspaceGalleryPage.tsx +219 -0
  52. package/template/core/src/openpress/app/index.ts +2 -0
  53. package/template/core/src/openpress/core/Frame.tsx +26 -15
  54. package/template/core/src/openpress/core/FrameContext.tsx +10 -3
  55. package/template/core/src/openpress/core/MdxArea.tsx +11 -12
  56. package/template/core/src/openpress/core/Press.tsx +25 -4
  57. package/template/core/src/openpress/core/Workspace.tsx +36 -0
  58. package/template/core/src/openpress/core/cn.ts +4 -0
  59. package/template/core/src/openpress/core/index.tsx +11 -3
  60. package/template/core/src/openpress/core/primitives.tsx +74 -6
  61. package/template/core/src/openpress/core/types.ts +94 -41
  62. package/template/core/src/openpress/core/useSource.ts +1 -1
  63. package/template/core/src/openpress/{anchorMap.ts → document-model/anchorMapModel.ts} +1 -1
  64. package/template/core/src/openpress/{indexes.ts → document-model/documentIndexes.ts} +1 -1
  65. package/template/core/src/openpress/{types.ts → document-model/documentTypes.ts} +51 -0
  66. package/template/core/src/openpress/document-model/index.ts +7 -0
  67. package/template/core/src/openpress/document-model/objectEntityModel.ts +55 -0
  68. package/template/core/src/openpress/{projectIdentity.ts → document-model/projectIdentityModel.ts} +1 -1
  69. package/template/core/src/openpress/{reactDocumentMetadata.ts → document-model/reactDocumentMetadataModel.ts} +1 -1
  70. package/template/core/src/openpress/document-model/workspaceManifestModel.ts +57 -0
  71. package/template/core/src/openpress/manuscript/index.tsx +49 -7
  72. package/template/core/src/openpress/mdx/index.ts +15 -7
  73. package/template/core/src/openpress/reader/PageThumbnailsPanel.tsx +168 -0
  74. package/template/core/src/openpress/{publicPage.tsx → reader/PublicReaderPage.tsx} +31 -51
  75. package/template/core/src/openpress/{workbenchPanels.tsx → reader/ReaderNavigationPanel.tsx} +6 -5
  76. package/template/core/src/openpress/reader/index.ts +11 -0
  77. package/template/core/src/openpress/reader/pageViewportScaleModel.ts +73 -0
  78. package/template/core/src/openpress/reader/readerTypes.ts +4 -0
  79. package/template/core/src/openpress/reader/usePageViewportScale.ts +119 -0
  80. package/template/core/src/openpress/reader/usePanelState.ts +56 -0
  81. package/template/core/src/openpress/reader/useReaderHashSync.ts +61 -0
  82. package/template/core/src/openpress/reader/useReaderKeyboardNav.ts +48 -0
  83. package/template/core/src/openpress/reader/useReaderRuntime.ts +146 -0
  84. package/template/core/src/openpress/reader/useReaderScrollAnchor.ts +64 -0
  85. package/template/core/src/openpress/shared/Panel.tsx +77 -0
  86. package/template/core/src/openpress/shared/index.ts +4 -0
  87. package/template/core/src/openpress/shared/numberUtils.ts +3 -0
  88. package/template/core/src/openpress/{runtimeMode.ts → shared/runtimeMode.ts} +0 -11
  89. package/template/core/src/openpress/workbench/Workbench.tsx +506 -0
  90. package/template/core/src/openpress/workbench/actions/DeploymentControl.tsx +157 -0
  91. package/template/core/src/openpress/workbench/actions/ExportImageControl.tsx +96 -0
  92. package/template/core/src/openpress/workbench/actions/PageZoomControl.tsx +182 -0
  93. package/template/core/src/openpress/workbench/actions/SearchControl.tsx +345 -0
  94. package/template/core/src/openpress/workbench/actions/deploymentStatusModel.ts +112 -0
  95. package/template/core/src/openpress/workbench/actions/index.ts +6 -0
  96. package/template/core/src/openpress/workbench/actions/useDeploymentWorkbench.ts +136 -0
  97. package/template/core/src/openpress/workbench/dialog/WorkbenchDialog.tsx +72 -0
  98. package/template/core/src/openpress/workbench/dialog/index.ts +1 -0
  99. package/template/core/src/openpress/workbench/document/components/DocumentPanel.tsx +127 -0
  100. package/template/core/src/openpress/workbench/document/components/InlineSourceEditorLayer.tsx +207 -0
  101. package/template/core/src/openpress/workbench/document/components/ReaderStage.tsx +9 -0
  102. package/template/core/src/openpress/workbench/document/hooks/useDocumentWorkbenchModel.ts +34 -0
  103. package/template/core/src/openpress/workbench/document/hooks/useInlineDocumentEditor.ts +525 -0
  104. package/template/core/src/openpress/workbench/document/index.ts +10 -0
  105. package/template/core/src/openpress/workbench/index.ts +2 -0
  106. package/template/core/src/openpress/workbench/inspector/InlineInspectorLayer.tsx +459 -0
  107. package/template/core/src/openpress/workbench/inspector/index.ts +5 -0
  108. package/template/core/src/openpress/workbench/inspector/inlineCommentModel.ts +125 -0
  109. package/template/core/src/openpress/workbench/inspector/inspectorGeometryModel.ts +160 -0
  110. package/template/core/src/openpress/workbench/inspector/inspectorModel.ts +408 -0
  111. package/template/core/src/openpress/workbench/inspector/useInspectorComments.ts +254 -0
  112. package/template/core/src/openpress/workbench/mentions/MentionSuggestionList.tsx +41 -0
  113. package/template/core/src/openpress/workbench/mentions/index.ts +2 -0
  114. package/template/core/src/openpress/{composerMentions.ts → workbench/mentions/useComposerMentions.ts} +1 -4
  115. package/template/core/src/openpress/workbench/panels/Panel.tsx +1 -0
  116. package/template/core/src/openpress/workbench/panels/PendingCommentsPanel.tsx +80 -0
  117. package/template/core/src/openpress/workbench/panels/WorkbenchControlPanel.tsx +29 -0
  118. package/template/core/src/openpress/workbench/panels/index.ts +3 -0
  119. package/template/core/src/openpress/workbench/project/ProjectEntryPanel.tsx +525 -0
  120. package/template/core/src/openpress/workbench/project/ProjectPreviewDialog.tsx +35 -0
  121. package/template/core/src/openpress/workbench/project/index.ts +2 -0
  122. package/template/core/src/openpress/workbench/project/projectPreviewTypes.ts +11 -0
  123. package/template/core/src/openpress/workbench/shell/WorkbenchShell.tsx +167 -0
  124. package/template/core/src/openpress/workbench/shell/index.ts +1 -0
  125. package/template/core/src/openpress/workbench/workbenchFormatters.ts +120 -0
  126. package/template/core/src/openpress/workbench/workbenchTypes.ts +35 -0
  127. package/template/core/src/styles/openpress/print-route.css +0 -2
  128. package/template/core/src/styles/openpress/{project-workspace.css → project-preview-panel.css} +13 -407
  129. package/template/core/src/styles/openpress/public-viewer.css +25 -320
  130. package/template/core/src/styles/openpress/reader-runtime.css +252 -55
  131. package/template/core/src/styles/openpress/responsive.css +145 -270
  132. package/template/core/src/styles/openpress/workbench-panels.css +327 -178
  133. package/template/core/src/styles/openpress/workbench.css +986 -451
  134. package/template/core/src/styles/openpress/workspace-gallery.css +300 -0
  135. package/template/core/src/styles/openpress.css +2 -1
  136. package/template/core/tsconfig.json +1 -1
  137. package/template/core/vite.config.ts +50 -0
  138. package/template/core/engine/commands/init.mjs +0 -24
  139. package/template/core/engine/init.mjs +0 -90
  140. package/template/core/src/openpress/App.tsx +0 -127
  141. package/template/core/src/openpress/inspector.ts +0 -282
  142. package/template/core/src/openpress/projectWorkspace.tsx +0 -919
  143. package/template/core/src/openpress/readerRuntime.ts +0 -230
  144. package/template/core/src/openpress/workbench.tsx +0 -1265
  145. package/template/core/src/openpress/workbenchTypes.ts +0 -4
  146. package/template/packs/academic-paper/document/chapters/01-introduction/content/01-introduction.mdx +0 -35
  147. package/template/packs/academic-paper/document/chapters/02-methods/content/01-methods.mdx +0 -50
  148. package/template/packs/academic-paper/document/chapters/03-results-and-discussion/content/01-results.mdx +0 -47
  149. package/template/packs/academic-paper/document/chapters/04-acknowledgment/content/01-acknowledgment.mdx +0 -26
  150. package/template/packs/academic-paper/document/chapters/05-references/content/01-references.mdx +0 -32
  151. package/template/packs/academic-paper/document/components/ChapterOpenerVisual/index.tsx +0 -76
  152. package/template/packs/academic-paper/document/components/Page.tsx +0 -60
  153. package/template/packs/academic-paper/document/components/TokenSwatchGrid/index.tsx +0 -46
  154. package/template/packs/academic-paper/document/components/TokenSwatchGrid/style.css +0 -63
  155. package/template/packs/academic-paper/document/components/TypeSpecimen/index.tsx +0 -38
  156. package/template/packs/academic-paper/document/components/TypeSpecimen/style.css +0 -111
  157. package/template/packs/academic-paper/document/design.md +0 -279
  158. package/template/packs/academic-paper/document/index.tsx +0 -123
  159. package/template/packs/academic-paper/document/media/README.md +0 -13
  160. package/template/packs/academic-paper/document/media/figure-placeholder.svg +0 -9
  161. package/template/packs/academic-paper/document/openpress.config.mjs +0 -26
  162. package/template/packs/academic-paper/document/theme/README.md +0 -11
  163. package/template/packs/academic-paper/document/theme/base/page-contract.css +0 -522
  164. package/template/packs/academic-paper/document/theme/base/print.css +0 -93
  165. package/template/packs/academic-paper/document/theme/base/typography.css +0 -333
  166. package/template/packs/academic-paper/document/theme/fonts.css +0 -3
  167. package/template/packs/academic-paper/document/theme/page-surfaces/back-cover.css +0 -43
  168. package/template/packs/academic-paper/document/theme/page-surfaces/chapter-opener.css +0 -205
  169. package/template/packs/academic-paper/document/theme/page-surfaces/cover.css +0 -294
  170. package/template/packs/academic-paper/document/theme/page-surfaces/toc.css +0 -149
  171. package/template/packs/academic-paper/document/theme/patterns/_chart-frame.css +0 -49
  172. package/template/packs/academic-paper/document/theme/patterns/figure-grid.css +0 -68
  173. package/template/packs/academic-paper/document/theme/patterns/table-utilities.css +0 -66
  174. package/template/packs/academic-paper/document/theme/shell/reader-controls.css +0 -761
  175. package/template/packs/academic-paper/document/theme/tokens.css +0 -80
  176. package/template/packs/academic-paper/openpress.config.mjs +0 -5
  177. package/template/packs/claude-document/document/chapters/01-document-shape/content/01-document-shape.mdx +0 -51
  178. package/template/packs/claude-document/document/chapters/02-review-loop/content/01-review-loop.mdx +0 -31
  179. package/template/packs/claude-document/document/components/ChapterOpenerVisual.tsx +0 -96
  180. package/template/packs/claude-document/document/components/Page.tsx +0 -37
  181. package/template/packs/claude-document/document/design.md +0 -142
  182. package/template/packs/claude-document/document/index.tsx +0 -94
  183. package/template/packs/claude-document/document/media/README.md +0 -13
  184. package/template/packs/claude-document/document/openpress.config.mjs +0 -26
  185. package/template/packs/claude-document/document/theme/README.md +0 -15
  186. package/template/packs/claude-document/document/theme/base/page-contract.css +0 -525
  187. package/template/packs/claude-document/document/theme/base/print.css +0 -93
  188. package/template/packs/claude-document/document/theme/base/typography.css +0 -612
  189. package/template/packs/claude-document/document/theme/fonts.css +0 -4
  190. package/template/packs/claude-document/document/theme/page-surfaces/back-cover.css +0 -72
  191. package/template/packs/claude-document/document/theme/page-surfaces/chapter-opener.css +0 -236
  192. package/template/packs/claude-document/document/theme/page-surfaces/cover.css +0 -309
  193. package/template/packs/claude-document/document/theme/page-surfaces/toc.css +0 -225
  194. package/template/packs/claude-document/document/theme/patterns/_chart-frame.css +0 -53
  195. package/template/packs/claude-document/document/theme/patterns/figure-grid.css +0 -68
  196. package/template/packs/claude-document/document/theme/patterns/table-utilities.css +0 -66
  197. package/template/packs/claude-document/document/theme/shell/reader-controls.css +0 -789
  198. package/template/packs/claude-document/document/theme/tokens.css +0 -89
  199. package/template/packs/claude-document/openpress.config.mjs +0 -5
  200. package/template/packs/editorial-monograph/document/chapters/01-product-and-use-cases/content/01-product-and-use-cases.mdx +0 -31
  201. package/template/packs/editorial-monograph/document/chapters/02-workflow/content/01-workflow.mdx +0 -89
  202. package/template/packs/editorial-monograph/document/chapters/03-agent-skills-contributors/content/01-agent-skills-contributors.mdx +0 -51
  203. package/template/packs/editorial-monograph/document/chapters/04-validation-deploy/content/01-validation-deploy.mdx +0 -39
  204. package/template/packs/editorial-monograph/document/components/ChapterOpenerVisual/index.tsx +0 -76
  205. package/template/packs/editorial-monograph/document/components/Page.tsx +0 -37
  206. package/template/packs/editorial-monograph/document/components/TokenSwatchGrid/index.tsx +0 -46
  207. package/template/packs/editorial-monograph/document/components/TokenSwatchGrid/style.css +0 -63
  208. package/template/packs/editorial-monograph/document/components/TypeSpecimen/index.tsx +0 -38
  209. package/template/packs/editorial-monograph/document/components/TypeSpecimen/style.css +0 -111
  210. package/template/packs/editorial-monograph/document/design.md +0 -279
  211. package/template/packs/editorial-monograph/document/index.tsx +0 -97
  212. package/template/packs/editorial-monograph/document/media/README.md +0 -13
  213. package/template/packs/editorial-monograph/document/openpress.config.mjs +0 -26
  214. package/template/packs/editorial-monograph/document/theme/README.md +0 -11
  215. package/template/packs/editorial-monograph/document/theme/base/page-contract.css +0 -505
  216. package/template/packs/editorial-monograph/document/theme/base/print.css +0 -93
  217. package/template/packs/editorial-monograph/document/theme/base/typography.css +0 -336
  218. package/template/packs/editorial-monograph/document/theme/fonts.css +0 -3
  219. package/template/packs/editorial-monograph/document/theme/page-surfaces/back-cover.css +0 -43
  220. package/template/packs/editorial-monograph/document/theme/page-surfaces/chapter-opener.css +0 -205
  221. package/template/packs/editorial-monograph/document/theme/page-surfaces/cover.css +0 -147
  222. package/template/packs/editorial-monograph/document/theme/page-surfaces/toc.css +0 -149
  223. package/template/packs/editorial-monograph/document/theme/patterns/_chart-frame.css +0 -49
  224. package/template/packs/editorial-monograph/document/theme/patterns/figure-grid.css +0 -68
  225. package/template/packs/editorial-monograph/document/theme/patterns/table-utilities.css +0 -66
  226. package/template/packs/editorial-monograph/document/theme/shell/reader-controls.css +0 -761
  227. package/template/packs/editorial-monograph/document/theme/tokens.css +0 -80
  228. package/template/packs/editorial-monograph/openpress.config.mjs +0 -5
  229. /package/template/core/src/openpress/{readerPageRegistry.ts → reader/readerPageRegistry.ts} +0 -0
  230. /package/template/core/src/openpress/{pageRoute.ts → reader/readerPageRoute.ts} +0 -0
  231. /package/template/core/src/openpress/{readerScroll.ts → reader/readerScroll.ts} +0 -0
  232. /package/template/core/src/openpress/{readerState.ts → reader/readerStateModel.ts} +0 -0
  233. /package/template/core/src/openpress/{frameScheduler.ts → shared/frameScheduler.ts} +0 -0
  234. /package/template/core/src/openpress/{projectSources.ts → workbench/project/projectSourceModel.ts} +0 -0
package/README.md CHANGED
@@ -2,16 +2,22 @@
2
2
 
3
3
  Scaffolder for [open-press](https://github.com/quan0715/open-press) — an AI-first fixed-layout document workspace.
4
4
 
5
+ ## Prerequisite
6
+
7
+ Node.js 20 or newer with `npm` / `npx`.
8
+
5
9
  ## Quick start
6
10
 
7
11
  ```bash
8
- npx @open-press/cli init my-doc --pack editorial-monograph
12
+ npx @open-press/cli init my-doc
9
13
  cd my-doc
10
14
  npm run dev
11
15
  ```
12
16
 
13
17
  Then open the local URL printed by Vite (typically `http://127.0.0.1:5173/?dev=1`).
14
18
 
19
+ The CLI creates the OpenPress runtime workspace only. Starters and examples live in skills, installed separately with `npx skills add <owner/repo>`. The starter-bearing skills in the framework repo are just skills; agents can read and use them directly.
20
+
15
21
  ## Usage
16
22
 
17
23
  ```
@@ -20,39 +26,49 @@ npx @open-press/cli init <target> [flags]
20
26
 
21
27
  | Flag | Description |
22
28
  | -------------------- | --------------------------------------------------------------------------- |
23
- | `--pack <name>` | Style pack starter: `editorial-monograph` or `claude-document` |
24
- | `--title <s>` | Document title (written to `openpress.config.mjs`) |
29
+ | `--title <s>` | Document title (written to workspace config) |
25
30
  | `--subtitle <s>` | Document subtitle |
26
31
  | `--organization <s>` | Organization name |
27
32
  | `--author <s>` | Author name |
28
- | `--no-git` | Skip `git init` |
29
- | `--no-install` | Skip `npm install` |
30
- | `--force` | Allow scaffolding into a non-empty target |
33
+ | `--no-git` | Skip `git init` + initial commit (use when scaffolding inside an existing repo) |
34
+ | `--no-install` | Skip `npm install` (offline, or you'll run pnpm/bun yourself) |
31
35
  | `--help` | Print help |
32
36
 
37
+ > The target must be empty. A `.git/` directory or other harmless dotfiles (`.gitignore`, `.gitkeep`, `.DS_Store`) are ignored — common when scaffolding into a fresh repo.
38
+
39
+ To use an opinionated starter, install a skill and let the agent read that skill's files:
40
+
41
+ ```bash
42
+ npx -y skills@latest add quan0715/openpress-social-card-skill
43
+ ```
44
+
33
45
  ## What it creates
34
46
 
35
47
  A self-contained workspace with:
36
48
 
37
49
  - `engine/`, `src/`, `vite.config.ts` — the open-press framework (snapshot of `@open-press/core`)
38
- - `document/` — your content (populated from the chosen style pack)
39
50
  - `.claude/skills/` and `.agents/skills/` — agent skill files for Claude Code, Codex, Cursor, Copilot, etc.
40
51
  - `openpress.config.mjs` — workspace metadata (title, subtitle, organization, author)
41
52
  - `AGENTS.md` — agent contract
42
53
 
54
+ The `press/` or transitional `document/` source tree is added by a skill, user-authored code, or a project-specific workflow after init.
55
+
43
56
  ## After init
44
57
 
45
58
  Workspace commands (run via `npm run` or `node engine/cli.mjs`):
46
59
 
47
60
  ```
48
- npm run dev # start workbench
49
- npm run build # render production output (dist-react/)
50
- npm run preview # preview production build
51
- npm run openpress:validate # structural checks
52
- npm run openpress:pdf # render PDF
53
- npm run openpress:deploy:dry-run
61
+ npm run dev # start workbench
62
+ npm run build # validate + render dist-react/
63
+ npm run preview # preview production build
64
+ npm run typecheck # tsc --noEmit
65
+ npm run openpress:image # render one PNG per page
66
+ npm run openpress:pdf # render PDF
67
+ npm run openpress:deploy:dry-run # preview deploy without publishing
54
68
  ```
55
69
 
70
+ Full reference: <https://open-press.dev/docs/cli>
71
+
56
72
  ## License
57
73
 
58
74
  MIT — see [LICENSE](https://github.com/quan0715/open-press/blob/main/LICENSE).
package/dist/cli.js CHANGED
@@ -6,61 +6,21 @@ import process2 from "process";
6
6
  // src/init.ts
7
7
  import { spawn } from "child_process";
8
8
  import { existsSync } from "fs";
9
- import { cp, mkdir as mkdir2, rm as rm2 } from "fs/promises";
10
- import path2 from "path";
9
+ import { cp, mkdir } from "fs/promises";
10
+ import path from "path";
11
11
  import process from "process";
12
12
  import { fileURLToPath } from "url";
13
13
 
14
- // src/degit.ts
15
- import { createWriteStream } from "fs";
16
- import { mkdir, rm, stat } from "fs/promises";
17
- import { tmpdir } from "os";
18
- import path from "path";
19
- import { Readable } from "stream";
20
- import { pipeline } from "stream/promises";
21
- import { x as extract } from "tar";
22
- async function degit({ owner, repo, ref = "main", dest, subdir }) {
23
- const url = `https://codeload.github.com/${owner}/${repo}/tar.gz/refs/heads/${ref}`;
24
- const tmpDir = await mkdir(path.join(tmpdir(), `open-press-degit-${Date.now()}`), { recursive: true });
25
- const tarballPath = path.join(tmpDir, "repo.tar.gz");
26
- try {
27
- await fetchTo(url, tarballPath);
28
- await mkdir(dest, { recursive: true });
29
- const subdirSegments = subdir ? subdir.split("/").filter(Boolean).length : 0;
30
- const totalStrip = 1 + subdirSegments;
31
- const filterPrefix = subdir ? subdir.replace(/\/$/, "") + "/" : null;
32
- await extract({
33
- file: tarballPath,
34
- cwd: dest,
35
- strip: totalStrip,
36
- filter: (filePath) => {
37
- const segments = filePath.split("/");
38
- const inside = segments.slice(1).join("/");
39
- if (filterPrefix) {
40
- return inside.startsWith(filterPrefix);
41
- }
42
- return true;
43
- }
44
- });
45
- } finally {
46
- await rm(tmpDir, { recursive: true, force: true }).catch(() => {
47
- });
48
- }
49
- }
50
- async function fetchTo(url, destFile) {
51
- const res = await fetch(url, { redirect: "follow" });
52
- if (!res.ok || !res.body) {
53
- throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
54
- }
55
- await pipeline(Readable.fromWeb(res.body), createWriteStream(destFile));
56
- }
57
- async function pathIsEmpty(target) {
14
+ // src/path-is-empty.ts
15
+ import { readdir, stat } from "fs/promises";
16
+ var HARMLESS_TARGET_ENTRIES = /* @__PURE__ */ new Set([".git", ".gitignore", ".gitkeep", ".DS_Store"]);
17
+ async function pathIsEmpty(target, options = {}) {
58
18
  try {
59
19
  const s = await stat(target);
60
20
  if (!s.isDirectory()) return false;
61
- const { readdir } = await import("fs/promises");
62
21
  const entries = await readdir(target);
63
- return entries.length === 0;
22
+ if (!options.ignoreHarmless) return entries.length === 0;
23
+ return entries.every((entry) => HARMLESS_TARGET_ENTRIES.has(entry));
64
24
  } catch {
65
25
  return true;
66
26
  }
@@ -68,20 +28,17 @@ async function pathIsEmpty(target) {
68
28
 
69
29
  // src/metadata.ts
70
30
  import { readFile, writeFile } from "fs/promises";
71
- async function patchOpenpressConfig(configPath, patch) {
72
- let source = await readFile(configPath, "utf8");
73
- for (const [key, value] of Object.entries(patch)) {
74
- if (value === void 0 || value === null || value === "") continue;
75
- const escaped = escapeStringForJs(value);
76
- const re = new RegExp(`(${key}\\s*:\\s*)("[^"]*"|'[^']*'|\`[^\`]*\`)`, "m");
77
- if (re.test(source)) {
78
- source = source.replace(re, `$1"${escaped}"`);
79
- } else {
80
- source = source.replace(/(export\s+default\s*\{)/, `$1
81
- ${key}: "${escaped}",`);
82
- }
31
+ async function patchPressTitle(entryPath, title) {
32
+ const source = await readFile(entryPath, "utf8");
33
+ const escaped = escapeStringForJs(title);
34
+ const existing = /(<Press\b[^>]*\btitle\s*=\s*)("[^"]*"|'[^']*'|\{`[^`]*`\})/;
35
+ let next;
36
+ if (existing.test(source)) {
37
+ next = source.replace(existing, `$1"${escaped}"`);
38
+ } else {
39
+ next = source.replace(/<Press\b/, `<Press title="${escaped}"`);
83
40
  }
84
- await writeFile(configPath, source);
41
+ await writeFile(entryPath, next);
85
42
  }
86
43
  function escapeStringForJs(value) {
87
44
  return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
@@ -115,69 +72,27 @@ async function patchPackageJsonName(packagePath, newName) {
115
72
  }
116
73
 
117
74
  // src/init.ts
118
- var BUNDLED_PACKS = ["editorial-monograph", "claude-document", "academic-paper"];
119
75
  var FRAMEWORK_SKILLS_SOURCE = "quan0715/open-press";
120
- var __dirname = path2.dirname(fileURLToPath(import.meta.url));
121
- var TEMPLATE_ROOT = path2.resolve(__dirname, "..", "template");
122
- var TEMPLATE_CORE = path2.join(TEMPLATE_ROOT, "core");
123
- var TEMPLATE_PACKS = path2.join(TEMPLATE_ROOT, "packs");
76
+ var __dirname = path.dirname(fileURLToPath(import.meta.url));
77
+ var TEMPLATE_ROOT = path.resolve(__dirname, "..", "template");
78
+ var TEMPLATE_CORE = path.join(TEMPLATE_ROOT, "core");
124
79
  async function init(options) {
125
- const packSpec = options.pack ? parsePackSpec(options.pack) : null;
126
80
  ensureTemplateBundled();
127
- const target = path2.resolve(process.cwd(), options.target);
128
- await ensureTarget(target, options.force);
81
+ const target = path.resolve(process.cwd(), options.target);
82
+ await ensureTarget(target);
129
83
  log(`Creating open-press workspace at ${target}`);
130
84
  log("Copying framework (engine + runtime + config)\u2026");
131
85
  await cp(TEMPLATE_CORE, target, { recursive: true });
132
- const docDest = path2.join(target, "document");
133
- await rm2(docDest, { recursive: true, force: true });
134
- await mkdir2(docDest, { recursive: true });
135
- if (packSpec?.kind === "bundled") {
136
- log(`Applying bundled style pack: ${packSpec.name}`);
137
- const packStarter = path2.join(TEMPLATE_PACKS, packSpec.name, "document");
138
- if (!existsSync(packStarter)) {
139
- throw new Error(`Bundled style pack starter not found: ${packStarter}`);
140
- }
141
- await cp(packStarter, docDest, { recursive: true });
142
- } else if (packSpec?.kind === "github") {
143
- log(`Fetching style pack from github:${packSpec.owner}/${packSpec.repo}${packSpec.ref ? `#${packSpec.ref}` : ""}\u2026`);
144
- try {
145
- await degit({
146
- owner: packSpec.owner,
147
- repo: packSpec.repo,
148
- ref: packSpec.ref,
149
- dest: docDest,
150
- subdir: "starter/document"
151
- });
152
- } catch (err) {
153
- throw new Error(
154
- `Failed to fetch pack from github:${packSpec.owner}/${packSpec.repo}: ${err instanceof Error ? err.message : String(err)}`
155
- );
156
- }
157
- if (await pathIsEmpty(docDest)) {
158
- throw new Error(
159
- `github:${packSpec.owner}/${packSpec.repo} doesn't contain starter/document/ at the repo root.
160
- Third-party pack repos should follow this layout:
161
- <repo>/
162
- \u251C\u2500\u2500 starter/
163
- \u2502 \u2514\u2500\u2500 document/ \u2190 cli copies this into your workspace's document/
164
- \u2514\u2500\u2500 skills/<pack>/SKILL.md \u2190 npx skills add picks this up`
165
- );
166
- }
167
- }
168
- const pkgPath = path2.join(target, "package.json");
86
+ const pkgPath = path.join(target, "package.json");
169
87
  if (existsSync(pkgPath)) {
170
- await patchPackageJsonName(pkgPath, path2.basename(target));
88
+ await patchPackageJsonName(pkgPath, path.basename(target));
171
89
  }
172
- const configPath = path2.join(target, "openpress.config.mjs");
173
- if (existsSync(configPath) && hasMetadata(options)) {
174
- log("Writing metadata into openpress.config.mjs");
175
- await patchOpenpressConfig(configPath, {
176
- title: options.title,
177
- subtitle: options.subtitle,
178
- organization: options.organization,
179
- author: options.author
180
- });
90
+ if (options.title) {
91
+ const pressEntry = path.join(target, "press", "index.tsx");
92
+ if (existsSync(pressEntry)) {
93
+ log("Writing title into <Press> in press/index.tsx");
94
+ await patchPressTitle(pressEntry, options.title);
95
+ }
181
96
  }
182
97
  log(`Installing framework skills via \`npx skills add ${FRAMEWORK_SKILLS_SOURCE}\`\u2026`);
183
98
  try {
@@ -186,16 +101,6 @@ Third-party pack repos should follow this layout:
186
101
  log(`(framework skills install failed; retry: npx skills add ${FRAMEWORK_SKILLS_SOURCE})`);
187
102
  log(` reason: ${err instanceof Error ? err.message : String(err)}`);
188
103
  }
189
- if (packSpec?.kind === "github") {
190
- const packSource = `${packSpec.owner}/${packSpec.repo}`;
191
- log(`Installing pack skills via \`npx skills add ${packSource}\`\u2026`);
192
- try {
193
- await runInTarget(target, "npx", ["-y", "skills@latest", "add", packSource]);
194
- } catch (err) {
195
- log(`(pack skills install failed; retry: npx skills add ${packSource})`);
196
- log(` reason: ${err instanceof Error ? err.message : String(err)}`);
197
- }
198
- }
199
104
  if (options.install) {
200
105
  log("Installing dependencies (npm install)\u2026");
201
106
  await runInTarget(target, "npm", ["install"]);
@@ -216,46 +121,24 @@ Third-party pack repos should follow this layout:
216
121
  }
217
122
  printNextSteps(target, options);
218
123
  }
219
- function parsePackSpec(spec) {
220
- if (spec.startsWith("github:")) {
221
- const rest = spec.slice("github:".length);
222
- const [pathPart, ref] = rest.split("#");
223
- const segments = pathPart.split("/").filter(Boolean);
224
- if (segments.length !== 2) {
225
- throw new Error(
226
- `Invalid --pack spec: "${spec}". Use github:owner/repo or github:owner/repo#ref.`
227
- );
228
- }
229
- const [owner, repo] = segments;
230
- return { kind: "github", owner, repo, ref: ref?.trim() || void 0 };
231
- }
232
- if (!BUNDLED_PACKS.includes(spec)) {
233
- throw new Error(
234
- `Unknown style pack: "${spec}". Bundled packs: ${BUNDLED_PACKS.join(", ")}. For third-party packs use github:owner/repo (e.g. github:quan0715/openpress-pack-nycu-thesis).`
235
- );
236
- }
237
- return { kind: "bundled", name: spec };
238
- }
239
124
  function ensureTemplateBundled() {
240
- if (!existsSync(TEMPLATE_CORE) || !existsSync(TEMPLATE_PACKS)) {
125
+ if (!existsSync(TEMPLATE_CORE)) {
241
126
  throw new Error(
242
127
  `Template not bundled at ${TEMPLATE_ROOT}. If running from source, run \`pnpm sync:template\` in packages/cli first.`
243
128
  );
244
129
  }
245
130
  }
246
- async function ensureTarget(target, force) {
131
+ async function ensureTarget(target) {
247
132
  if (existsSync(target)) {
248
- if (force) return;
249
- const empty = await pathIsEmpty(target);
133
+ const empty = await pathIsEmpty(target, { ignoreHarmless: true });
250
134
  if (!empty) {
251
- throw new Error(`Target ${target} is not empty. Pass --force to scaffold into it anyway.`);
135
+ throw new Error(
136
+ `Target ${target} is not empty. Remove existing files first, or scaffold into a different directory.`
137
+ );
252
138
  }
253
139
  return;
254
140
  }
255
- await mkdir2(target, { recursive: true });
256
- }
257
- function hasMetadata(options) {
258
- return Boolean(options.title || options.subtitle || options.organization || options.author);
141
+ await mkdir(target, { recursive: true });
259
142
  }
260
143
  async function runInTarget(cwd, command, args, opts = {}) {
261
144
  return new Promise((resolve, reject) => {
@@ -276,7 +159,7 @@ function log(message) {
276
159
  `);
277
160
  }
278
161
  function printNextSteps(target, options) {
279
- const rel = path2.relative(process.cwd(), target) || ".";
162
+ const rel = path.relative(process.cwd(), target) || ".";
280
163
  const lines = [
281
164
  "",
282
165
  "\u2713 Done. Your open-press workspace is ready.",
@@ -297,7 +180,7 @@ function printNextSteps(target, options) {
297
180
  "Agent skills installed under .agents/skills/ (universal \u2014 read by Claude Code,",
298
181
  `Cursor, Codex, Gemini CLI, etc.). Update later with: npx skills upgrade`,
299
182
  "",
300
- "Edit content under document/chapters/, or ask your AI agent to help.",
183
+ "Use an OpenPress-ready skill to add or adapt the press/document source tree.",
301
184
  ""
302
185
  );
303
186
  process.stdout.write(lines.join("\n"));
@@ -310,28 +193,14 @@ Usage:
310
193
  npx @open-press/cli init <target> [flags]
311
194
 
312
195
  Flags:
313
- --pack <spec> Style pack source. Either:
314
- \u2022 a bundled name \u2014 editorial-monograph | claude-document | academic-paper
315
- \u2022 github:owner/repo (third-party pack)
316
- \u2022 github:owner/repo#branch-or-tag
317
- --title <s> Document title (written to openpress.config.mjs)
318
- --subtitle <s> Document subtitle
319
- --organization <s> Organization name
320
- --author <s> Author name
196
+ --title <s> Document title (written into <Press title="..."> in press/index.tsx)
321
197
  --no-git Skip git init
322
198
  --no-install Skip npm install
323
- --force Allow non-empty target
324
199
  --help Show this help
325
200
 
326
201
  Examples:
327
- # Bundled
328
- npx @open-press/cli init my-doc --pack editorial-monograph
329
- npx @open-press/cli init my-brief --pack claude-document --title "Q2 Brief" --author Quan
330
- npx @open-press/cli init my-paper --pack academic-paper --title "Paper Title" --author "First Author"
331
-
332
- # Third-party (any GitHub repo with starter/document/ at the root)
333
- npx @open-press/cli init my-thesis --pack github:quan0715/openpress-pack-nycu-thesis
334
- npx @open-press/cli init my-paper --pack github:foo/their-pack#v1.2
202
+ npx @open-press/cli init my-doc
203
+ npx @open-press/cli init my-brief --title "Q2 Brief"
335
204
  `;
336
205
  async function main(argv) {
337
206
  if (argv.length === 0 || argv.includes("--help") || argv.includes("-h")) {
@@ -368,33 +237,16 @@ function parseInitArgs(args) {
368
237
  }
369
238
  const options = {
370
239
  target: "",
371
- pack: void 0,
372
240
  title: void 0,
373
- subtitle: void 0,
374
- organization: void 0,
375
- author: void 0,
376
241
  git: true,
377
- install: true,
378
- force: false
242
+ install: true
379
243
  };
380
244
  for (let i = 0; i < args.length; i++) {
381
245
  const arg = args[i];
382
246
  switch (arg) {
383
- case "--pack":
384
- options.pack = args[++i];
385
- break;
386
247
  case "--title":
387
248
  options.title = args[++i];
388
249
  break;
389
- case "--subtitle":
390
- options.subtitle = args[++i];
391
- break;
392
- case "--organization":
393
- options.organization = args[++i];
394
- break;
395
- case "--author":
396
- options.author = args[++i];
397
- break;
398
250
  case "--no-git":
399
251
  options.git = false;
400
252
  break;
@@ -407,9 +259,6 @@ function parseInitArgs(args) {
407
259
  case "--install":
408
260
  options.install = true;
409
261
  break;
410
- case "--force":
411
- options.force = true;
412
- break;
413
262
  default:
414
263
  if (arg.startsWith("--")) {
415
264
  process2.stderr.write(`Unknown flag: ${arg}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-press/cli",
3
- "version": "0.7.1",
3
+ "version": "1.0.0",
4
4
  "type": "module",
5
5
  "description": "Scaffolder for open-press — AI-first fixed-layout document workspaces.",
6
6
  "license": "MIT",
@@ -40,9 +40,7 @@
40
40
  "engines": {
41
41
  "node": ">=20"
42
42
  },
43
- "dependencies": {
44
- "tar": "^7.5.0"
45
- },
43
+ "dependencies": {},
46
44
  "devDependencies": {
47
45
  "@types/node": "^25.8.0",
48
46
  "tsup": "^8.5.0",
@@ -52,6 +50,7 @@
52
50
  "sync:template": "node scripts/sync-template.mjs",
53
51
  "build": "pnpm sync:template && tsup",
54
52
  "dev": "tsup --watch",
55
- "typecheck": "tsc --noEmit"
53
+ "typecheck": "tsc --noEmit",
54
+ "test": "pnpm build && node --test tests/*.test.mjs"
56
55
  }
57
56
  }
@@ -16,15 +16,19 @@ will rewrite it.
16
16
 
17
17
  ```bash
18
18
  npm run dev # workbench at http://127.0.0.1:5173/?dev=1
19
- npm run openpress:validate # structural checks
20
- npm run openpress:render # full render through chromium
19
+ npm run build # validate + render dist-react/
20
+ npm run openpress:image # write dist-react/images/page-*.png
21
21
  npm run openpress:pdf # write document.pdf
22
- npm run openpress:export # write public/openpress/document.json
23
22
  npm run openpress:deploy # deploy via the configured adapter
24
23
  npx open-press doctor # current vs latest version + pending migrations
25
24
  npx open-press upgrade # apply the upgrade flow (see below)
26
25
  ```
27
26
 
27
+ The intermediate engine steps live behind `node engine/cli.mjs` if you
28
+ need them directly (rarely): `validate` (source-level checks only,
29
+ fast), `export` (write `public/openpress/document.json` without
30
+ bundling), `inspect` (post-render geometry + comment markers).
31
+
28
32
  ## When the user asks to upgrade
29
33
 
30
34
  Triggers: "升級 / 套件更新 / upgrade open-press / apply latest design /
@@ -44,8 +48,7 @@ update to vX.Y.Z" etc.
44
48
  Apply to `document/` with user confirmation.
45
49
  5. Verify:
46
50
  ```bash
47
- npm run openpress:validate
48
- npm run openpress:render
51
+ npm run build
49
52
  ```
50
53
  Fix anything broken using the migration notes.
51
54
  6. Report to the user: starting version → ending version, what was
@@ -73,32 +76,33 @@ regenerate `document.json`. So edits to:
73
76
  the change:
74
77
 
75
78
  ```bash
76
- npm run openpress:export # regenerate public/openpress/document.json
79
+ npm run build # validate + render (includes the export step)
77
80
  # then refresh the browser
81
+ # — or, for the inner export only, without the full Vite bundle step:
82
+ node engine/cli.mjs export .
78
83
  ```
79
84
 
80
85
  Quick rules of thumb:
81
86
 
82
87
  - Pure CSS edits under `document/theme/` that don't move blocks → HMR
83
88
  is enough (CSS is hot-replaced).
84
- - Anything that affects content, pagination, or metadata → re-export.
85
- - `npm run openpress:render` is `export` + extra asset sync; either
86
- works to refresh the JSON.
89
+ - Anything that affects content, pagination, or metadata → re-build (or
90
+ call `node engine/cli.mjs export .` for just the JSON refresh).
87
91
 
88
92
  **Agent SOP**: after applying any non-CSS edit to `document/`, run
89
- `npm run openpress:export` before telling the user "done". If they ask
90
- "why didn't my change show up?", check whether `document.json` was
93
+ `npm run build` before telling the user "done". If they ask "why
94
+ didn't my change show up?", check whether `document.json` was
91
95
  regenerated since the edit.
92
96
 
93
97
  ## When the user reports a render / paginate issue
94
98
 
95
99
  Press Tree paginates at build time. Common things to check:
96
100
 
97
- 1. `npm run openpress:export` then inspect
101
+ 1. `npm run build` then inspect
98
102
  `public/openpress/document.json` for `source.warnings` (chain
99
103
  overflow, missing chains, etc.).
100
- 2. `npm run openpress:validate` for structural issues
101
- (missing entries, broken anchors).
104
+ 2. `node engine/cli.mjs validate .` for structural issues
105
+ (missing entries, broken anchors) — faster than a full build.
102
106
  3. `npm run dev` and use the workbench inspector to find which MDX
103
107
  block / Frame element is misbehaving — comments and inline
104
108
  annotations work directly from there.