@open-press/cli 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/package.json +1 -1
- package/template/core/AGENTS.md +126 -0
- package/template/core/CHANGELOG.md +65 -0
- package/template/core/engine/commands/dev.mjs +2 -2
- package/template/core/engine/commands/upgrade.mjs +47 -5
- package/template/core/engine/output/chrome-pdf.mjs +18 -3
- package/template/core/engine/output/static-server.mjs +39 -0
- package/template/core/engine/react/comment-endpoint.mjs +13 -39
- package/template/core/engine/react/comment-marker.mjs +30 -6
- package/template/core/engine/react/document-entry.mjs +11 -0
- package/template/core/engine/react/document-export.mjs +45 -5
- package/template/core/engine/react/http-json.mjs +24 -0
- package/template/core/engine/react/mdx-compile.mjs +187 -3
- package/template/core/engine/react/measurement-css.mjs +93 -1
- package/template/core/engine/react/object-entities.mjs +119 -0
- package/template/core/engine/react/pipeline/allocate.mjs +10 -7
- package/template/core/engine/react/pipeline/frame-measurement.mjs +40 -9
- package/template/core/engine/react/project-asset-endpoint.mjs +6 -24
- package/template/core/engine/react/source-edit-endpoint.d.mts +10 -0
- package/template/core/engine/react/source-edit-endpoint.mjs +75 -0
- package/template/core/engine/react/sources/mdx-resolver.mjs +12 -14
- package/template/core/engine/react/style-discovery.mjs +1 -4
- package/template/core/engine/runtime/file-walk.mjs +22 -0
- package/template/core/engine/runtime/inspection.mjs +1 -20
- package/template/core/engine/runtime/path-utils.mjs +20 -0
- package/template/core/engine/runtime/source-text-tools.d.mts +102 -0
- package/template/core/engine/runtime/source-text-tools.mjs +551 -16
- package/template/core/engine/runtime/source-workspace.mjs +4 -31
- package/template/core/package.json +1 -1
- package/template/core/src/main.tsx +2 -2
- package/template/core/src/openpress/{App.tsx → app/OpenPressApp.tsx} +25 -12
- package/template/core/src/openpress/{renderer.tsx → app/OpenPressRuntime.tsx} +10 -7
- package/template/core/src/openpress/app/index.ts +2 -0
- package/template/core/src/openpress/core/Frame.tsx +9 -11
- package/template/core/src/openpress/core/FrameContext.tsx +8 -3
- package/template/core/src/openpress/core/MdxArea.tsx +11 -12
- package/template/core/src/openpress/core/cn.ts +4 -0
- package/template/core/src/openpress/core/index.tsx +2 -1
- package/template/core/src/openpress/core/primitives.tsx +29 -8
- package/template/core/src/openpress/core/types.ts +8 -0
- package/template/core/src/openpress/{anchorMap.ts → document-model/anchorMapModel.ts} +1 -1
- package/template/core/src/openpress/{indexes.ts → document-model/documentIndexes.ts} +1 -1
- package/template/core/src/openpress/{types.ts → document-model/documentTypes.ts} +42 -0
- package/template/core/src/openpress/document-model/index.ts +6 -0
- package/template/core/src/openpress/document-model/objectEntityModel.ts +51 -0
- package/template/core/src/openpress/{projectIdentity.ts → document-model/projectIdentityModel.ts} +1 -1
- package/template/core/src/openpress/{reactDocumentMetadata.ts → document-model/reactDocumentMetadataModel.ts} +1 -1
- package/template/core/src/openpress/manuscript/index.tsx +49 -7
- package/template/core/src/openpress/{publicPage.tsx → reader/PublicReaderPage.tsx} +31 -51
- package/template/core/src/openpress/{workbenchPanels.tsx → reader/ReaderNavigationPanel.tsx} +6 -5
- package/template/core/src/openpress/reader/index.ts +10 -0
- package/template/core/src/openpress/reader/pageViewportScaleModel.ts +73 -0
- package/template/core/src/openpress/reader/readerTypes.ts +4 -0
- package/template/core/src/openpress/reader/usePageViewportScale.ts +119 -0
- package/template/core/src/openpress/reader/usePanelState.ts +56 -0
- package/template/core/src/openpress/reader/useReaderHashSync.ts +61 -0
- package/template/core/src/openpress/reader/useReaderKeyboardNav.ts +48 -0
- package/template/core/src/openpress/reader/useReaderRuntime.ts +146 -0
- package/template/core/src/openpress/reader/useReaderScrollAnchor.ts +64 -0
- package/template/core/src/openpress/shared/Panel.tsx +77 -0
- package/template/core/src/openpress/shared/index.ts +4 -0
- package/template/core/src/openpress/shared/numberUtils.ts +3 -0
- package/template/core/src/openpress/{runtimeMode.ts → shared/runtimeMode.ts} +0 -11
- package/template/core/src/openpress/workbench/Workbench.tsx +407 -0
- package/template/core/src/openpress/workbench/actions/DeploymentControl.tsx +157 -0
- package/template/core/src/openpress/workbench/actions/PageZoomControl.tsx +182 -0
- package/template/core/src/openpress/workbench/actions/SearchControl.tsx +345 -0
- package/template/core/src/openpress/workbench/actions/deploymentStatusModel.ts +112 -0
- package/template/core/src/openpress/workbench/actions/index.ts +5 -0
- package/template/core/src/openpress/workbench/actions/useDeploymentWorkbench.ts +136 -0
- package/template/core/src/openpress/workbench/dialog/WorkbenchDialog.tsx +72 -0
- package/template/core/src/openpress/workbench/dialog/index.ts +1 -0
- package/template/core/src/openpress/workbench/document/components/DocumentPanel.tsx +127 -0
- package/template/core/src/openpress/workbench/document/components/InlineSourceEditorLayer.tsx +207 -0
- package/template/core/src/openpress/workbench/document/components/ReaderStage.tsx +9 -0
- package/template/core/src/openpress/workbench/document/hooks/useDocumentWorkbenchModel.ts +34 -0
- package/template/core/src/openpress/workbench/document/hooks/useInlineDocumentEditor.ts +525 -0
- package/template/core/src/openpress/workbench/document/index.ts +10 -0
- package/template/core/src/openpress/workbench/index.ts +2 -0
- package/template/core/src/openpress/workbench/inspector/InlineInspectorLayer.tsx +459 -0
- package/template/core/src/openpress/workbench/inspector/index.ts +5 -0
- package/template/core/src/openpress/workbench/inspector/inlineCommentModel.ts +125 -0
- package/template/core/src/openpress/workbench/inspector/inspectorGeometryModel.ts +160 -0
- package/template/core/src/openpress/workbench/inspector/inspectorModel.ts +408 -0
- package/template/core/src/openpress/workbench/inspector/useInspectorComments.ts +248 -0
- package/template/core/src/openpress/workbench/mentions/MentionSuggestionList.tsx +41 -0
- package/template/core/src/openpress/workbench/mentions/index.ts +2 -0
- package/template/core/src/openpress/{composerMentions.ts → workbench/mentions/useComposerMentions.ts} +1 -4
- package/template/core/src/openpress/workbench/panels/Panel.tsx +1 -0
- package/template/core/src/openpress/workbench/panels/PendingCommentsPanel.tsx +76 -0
- package/template/core/src/openpress/workbench/panels/WorkbenchControlPanel.tsx +29 -0
- package/template/core/src/openpress/workbench/panels/index.ts +3 -0
- package/template/core/src/openpress/workbench/project/ProjectEntryPanel.tsx +523 -0
- package/template/core/src/openpress/workbench/project/ProjectPreviewDialog.tsx +35 -0
- package/template/core/src/openpress/workbench/project/index.ts +2 -0
- package/template/core/src/openpress/workbench/project/projectPreviewTypes.ts +11 -0
- package/template/core/src/openpress/workbench/shell/WorkbenchShell.tsx +167 -0
- package/template/core/src/openpress/workbench/shell/index.ts +1 -0
- package/template/core/src/openpress/workbench/workbenchFormatters.ts +120 -0
- package/template/core/src/openpress/workbench/workbenchTypes.ts +35 -0
- package/template/core/src/styles/openpress/print-route.css +0 -2
- package/template/core/src/styles/openpress/{project-workspace.css → project-preview-panel.css} +13 -407
- package/template/core/src/styles/openpress/public-viewer.css +25 -320
- package/template/core/src/styles/openpress/reader-runtime.css +243 -55
- package/template/core/src/styles/openpress/responsive.css +145 -270
- package/template/core/src/styles/openpress/workbench-panels.css +214 -178
- package/template/core/src/styles/openpress/workbench.css +986 -451
- package/template/core/src/styles/openpress.css +1 -1
- package/template/core/vite.config.ts +50 -0
- package/template/packs/academic-paper/document/chapters/01-introduction/content/01-introduction.mdx +26 -12
- package/template/packs/academic-paper/document/chapters/02-methods/content/01-methods.mdx +37 -17
- package/template/packs/academic-paper/document/chapters/03-results-and-discussion/content/01-results.mdx +34 -16
- package/template/packs/academic-paper/document/chapters/04-acknowledgment/content/01-acknowledgment.mdx +22 -8
- package/template/packs/academic-paper/document/chapters/05-references/content/01-references.mdx +20 -15
- package/template/packs/academic-paper/document/components/Page.tsx +26 -3
- package/template/packs/academic-paper/document/index.tsx +51 -59
- package/template/packs/academic-paper/document/media/figure-placeholder.svg +9 -0
- package/template/packs/academic-paper/document/theme/base/page-contract.css +30 -13
- package/template/packs/academic-paper/document/theme/base/typography.css +30 -33
- package/template/packs/academic-paper/document/theme/page-surfaces/cover.css +74 -47
- package/template/core/src/openpress/inspector.ts +0 -282
- package/template/core/src/openpress/projectWorkspace.tsx +0 -919
- package/template/core/src/openpress/readerRuntime.ts +0 -230
- package/template/core/src/openpress/workbench.tsx +0 -1265
- package/template/core/src/openpress/workbenchTypes.ts +0 -4
- /package/template/core/src/openpress/{readerPageRegistry.ts → reader/readerPageRegistry.ts} +0 -0
- /package/template/core/src/openpress/{pageRoute.ts → reader/readerPageRoute.ts} +0 -0
- /package/template/core/src/openpress/{readerScroll.ts → reader/readerScroll.ts} +0 -0
- /package/template/core/src/openpress/{readerState.ts → reader/readerStateModel.ts} +0 -0
- /package/template/core/src/openpress/{frameScheduler.ts → shared/frameScheduler.ts} +0 -0
- /package/template/core/src/openpress/{projectSources.ts → workbench/project/projectSourceModel.ts} +0 -0
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
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
|
|
@@ -20,7 +24,7 @@ npx @open-press/cli init <target> [flags]
|
|
|
20
24
|
|
|
21
25
|
| Flag | Description |
|
|
22
26
|
| -------------------- | --------------------------------------------------------------------------- |
|
|
23
|
-
| `--pack <name>` | Style pack starter: `editorial-monograph` or `
|
|
27
|
+
| `--pack <name>` | Style pack starter: `editorial-monograph`, `claude-document`, or `academic-paper` |
|
|
24
28
|
| `--title <s>` | Document title (written to `openpress.config.mjs`) |
|
|
25
29
|
| `--subtitle <s>` | Document subtitle |
|
|
26
30
|
| `--organization <s>` | Organization name |
|
|
@@ -46,6 +50,7 @@ Workspace commands (run via `npm run` or `node engine/cli.mjs`):
|
|
|
46
50
|
|
|
47
51
|
```
|
|
48
52
|
npm run dev # start workbench
|
|
53
|
+
npm run openpress:export # refresh public/openpress/document.json
|
|
49
54
|
npm run build # render production output (dist-react/)
|
|
50
55
|
npm run preview # preview production build
|
|
51
56
|
npm run openpress:validate # structural checks
|
package/package.json
CHANGED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Working on this open-press workspace
|
|
2
|
+
|
|
3
|
+
This directory is an **open-press workspace** scaffolded by
|
|
4
|
+
`@open-press/cli`. You (the agent) own:
|
|
5
|
+
|
|
6
|
+
- `document/` — chapters (MDX), components, theme, media. The actual content.
|
|
7
|
+
- `package.json` / `openpress.config.mjs` — project metadata + build config.
|
|
8
|
+
- `.agents/skills/` — agent skills installed by `npx skills` (auto-refreshed via `npx open-press upgrade`).
|
|
9
|
+
|
|
10
|
+
The rest of the tree is the open-press framework copied at scaffold time
|
|
11
|
+
(`engine/`, `src/`, `vite.config.ts`, etc). Treat it as vendored — don't
|
|
12
|
+
hand-edit unless the user explicitly asks; the next `npx open-press upgrade`
|
|
13
|
+
will rewrite it.
|
|
14
|
+
|
|
15
|
+
## Quick reference
|
|
16
|
+
|
|
17
|
+
```bash
|
|
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
|
|
21
|
+
npm run openpress:pdf # write document.pdf
|
|
22
|
+
npm run openpress:export # write public/openpress/document.json
|
|
23
|
+
npm run openpress:deploy # deploy via the configured adapter
|
|
24
|
+
npx open-press doctor # current vs latest version + pending migrations
|
|
25
|
+
npx open-press upgrade # apply the upgrade flow (see below)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## When the user asks to upgrade
|
|
29
|
+
|
|
30
|
+
Triggers: "升級 / 套件更新 / upgrade open-press / apply latest design /
|
|
31
|
+
update to vX.Y.Z" etc.
|
|
32
|
+
|
|
33
|
+
**Follow the upgrade SOP, do NOT manually diff template versions:**
|
|
34
|
+
|
|
35
|
+
1. `npx open-press doctor` — confirm current vs latest, count pending
|
|
36
|
+
migrations.
|
|
37
|
+
2. Ask the user "go ahead?" — briefly mention what will change (deps,
|
|
38
|
+
skills, migrations to read).
|
|
39
|
+
3. `npx open-press upgrade` — refreshes `@open-press/core`, refreshes
|
|
40
|
+
installed skills, **fetches migration notes for each pending version
|
|
41
|
+
into `.openpress/migrations/<version>.md`** and lists the paths.
|
|
42
|
+
4. For each migration file listed, read it fully. Each has a
|
|
43
|
+
`Document-level changes` section with `rg` find + rewrite rules.
|
|
44
|
+
Apply to `document/` with user confirmation.
|
|
45
|
+
5. Verify:
|
|
46
|
+
```bash
|
|
47
|
+
npm run openpress:validate
|
|
48
|
+
npm run openpress:render
|
|
49
|
+
```
|
|
50
|
+
Fix anything broken using the migration notes.
|
|
51
|
+
6. Report to the user: starting version → ending version, what was
|
|
52
|
+
applied, anything that needed manual judgement.
|
|
53
|
+
|
|
54
|
+
**Anti-pattern**: running `npx @open-press/cli@latest init` somewhere
|
|
55
|
+
and manually diffing against the workspace. The migration notes are the
|
|
56
|
+
authoritative source for what changed; fresh templates ship default
|
|
57
|
+
content that does not apply to a customised workspace.
|
|
58
|
+
|
|
59
|
+
## When the user says "I changed X but the page didn't update"
|
|
60
|
+
|
|
61
|
+
Common cause: **the reader renders from a static `public/openpress/document.json`,
|
|
62
|
+
not from your live MDX / theme files.** Vite Hot Reload covers React UI
|
|
63
|
+
chrome (workbench panels, inspector, navigation) but it does **not**
|
|
64
|
+
regenerate `document.json`. So edits to:
|
|
65
|
+
|
|
66
|
+
- `document/chapters/**/*.mdx` (prose)
|
|
67
|
+
- `document/index.tsx` (Press tree, Cover/BackCover JSX)
|
|
68
|
+
- `document/components/**/*.tsx` (Page, openers, custom components)
|
|
69
|
+
- `document/theme/**` style files that affect pagination capacity
|
|
70
|
+
- `openpress.config.mjs` metadata (title, captionNumbering, …)
|
|
71
|
+
|
|
72
|
+
…all need a re-export before the workbench / public viewer reflect
|
|
73
|
+
the change:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm run openpress:export # regenerate public/openpress/document.json
|
|
77
|
+
# then refresh the browser
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Quick rules of thumb:
|
|
81
|
+
|
|
82
|
+
- Pure CSS edits under `document/theme/` that don't move blocks → HMR
|
|
83
|
+
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.
|
|
87
|
+
|
|
88
|
+
**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
|
|
91
|
+
regenerated since the edit.
|
|
92
|
+
|
|
93
|
+
## When the user reports a render / paginate issue
|
|
94
|
+
|
|
95
|
+
Press Tree paginates at build time. Common things to check:
|
|
96
|
+
|
|
97
|
+
1. `npm run openpress:export` then inspect
|
|
98
|
+
`public/openpress/document.json` for `source.warnings` (chain
|
|
99
|
+
overflow, missing chains, etc.).
|
|
100
|
+
2. `npm run openpress:validate` for structural issues
|
|
101
|
+
(missing entries, broken anchors).
|
|
102
|
+
3. `npm run dev` and use the workbench inspector to find which MDX
|
|
103
|
+
block / Frame element is misbehaving — comments and inline
|
|
104
|
+
annotations work directly from there.
|
|
105
|
+
|
|
106
|
+
## Skills
|
|
107
|
+
|
|
108
|
+
This workspace ships agent skills under `.agents/skills/`. If your
|
|
109
|
+
platform supports skills (Claude Code, Cursor, Codex, Cline, Gemini
|
|
110
|
+
CLI, …), prefer invoking them over re-reading this file:
|
|
111
|
+
|
|
112
|
+
- `openpress` — operate the workspace (CLI, validate, export, render,
|
|
113
|
+
PDF, deploy, search/replace, comments, upgrades, routing).
|
|
114
|
+
- `openpress-writing` — writing-time rules for MDX prose.
|
|
115
|
+
- `openpress-design` — theme tokens, layout, page surfaces.
|
|
116
|
+
- `openpress-deploy` — deployment workflows.
|
|
117
|
+
- `openpress-init` — scaffolding new workspaces.
|
|
118
|
+
- Plus any style-pack-specific skills installed by the user.
|
|
119
|
+
|
|
120
|
+
Skills are kept in sync by `npx skills upgrade` (run automatically
|
|
121
|
+
inside `npx open-press upgrade`).
|
|
122
|
+
|
|
123
|
+
## Reporting issues
|
|
124
|
+
|
|
125
|
+
- Issues / questions: https://github.com/quan0715/open-press/issues
|
|
126
|
+
- Source: https://github.com/quan0715/open-press
|
|
@@ -1,5 +1,70 @@
|
|
|
1
1
|
# @open-press/core
|
|
2
2
|
|
|
3
|
+
## 0.8.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- **Workbench architecture**: the monolithic `workbench.tsx` is split into a modular structure under `workbench/{shell,panels,actions,inspector,mentions,project,document}/`. New panels: `DeploymentControl`, `SearchControl`, `PendingCommentsPanel`, `DocumentPanel`, `ProjectEntryPanel`, plus `WorkbenchShell` and `InlineInspectorLayer`.
|
|
8
|
+
- **Module reorganization**: source tree split into typed subdirectories:
|
|
9
|
+
- `app/`: `OpenPressApp`, `OpenPressRuntime` (replaces the old `App.tsx` + `renderer.tsx`)
|
|
10
|
+
- `document-model/`: `anchorMap`, `documentIndexes`, `documentTypes`, `objectEntityModel`, `projectIdentity`, `reactDocumentMetadata`
|
|
11
|
+
- `reader/`: `PublicReaderPage`, `ReaderNavigationPanel`, `useReaderRuntime`, registry/route/scroll/state helpers
|
|
12
|
+
- `shared/`: `frameScheduler`, `runtimeMode`, `Panel`, `numberUtils`
|
|
13
|
+
- **Object-entity model**: `Frame` and `MdxArea` now expose `data-openpress-object-id`. New `document-model/objectEntityModel` defines the id format.
|
|
14
|
+
- **`MediaFigure` / `ImageFigure`**: new core primitives that accept `src/alt/caption` and resolve relative paths to `/openpress/media/...` automatically.
|
|
15
|
+
- **`<Sections>` default page**: `page` prop becomes optional; when omitted the built-in `DefaultSectionPage` renders the standard manuscript frame.
|
|
16
|
+
- **Engine helpers**: new `engine/react/{http-json,object-entities,source-edit-endpoint}.mjs` and `engine/runtime/{file-walk,path-utils}.mjs` runtime helpers. `engine/runtime/source-text-tools` exports TypeScript definitions.
|
|
17
|
+
- **Dev endpoints**: vite plugin wires `/__openpress/search` and `/__openpress/source-edit` middlewares for the new workbench search + inline editing flows.
|
|
18
|
+
- **Inline source editor**: ships the `InlineSourceEditorLayer` UI on top of `useInlineDocumentEditor` + `/__openpress/source-edit`. The hook now uses a `MutationObserver` so newly inserted blocks become editable, and routes mouse clicks through `focus()` to preserve selection on `contenteditable` boundaries. Workbench wires `sourceEditorTarget` state into the layer.
|
|
19
|
+
- **Table editing in the source pipeline**: table captions are emitted as standalone source blocks (`kind=element`, `name=caption`, `layout="attached"`) with `data-openpress-block-id`/`data-openpress-object-id` markers and preserved source positions; the allocator treats `layout="attached"` blocks as non-paginable. `applySourceBlockTableCellEditToText` (in `engine/runtime/source-text-tools`) accepts a `cellIndex` so the inline source editor can target a single `<td>`.
|
|
20
|
+
- **Reader pagination**: arrow-key pagination now defers to the user's active text selection. Shift-arrow / mouse-drag selections no longer get swallowed by the page-turn shortcut.
|
|
21
|
+
- **Page zoom + spread layout**: new `reader/pageViewportScaleModel` + `usePageViewportScale` hook drive a `--openpress-page-viewport-scale` CSS variable on the page container; the workbench toolbar exposes a `PageZoomControl` dropdown with fit-width / fit-page / fixed percentages plus a one-page / two-page spread toggle.
|
|
22
|
+
- **Inspector cell-precision comments**: `CommentDraft` gains an optional `targetObjectId` so a comment can point at a sub-block (e.g. a single table cell) while still attributing the source position to its enclosing block. `formatInspectorHint` carries the value through to the wire hint.
|
|
23
|
+
- **Shared `WorkbenchDialog` shell**: portal + backdrop + header (eyebrow / title / title-meta / close) + optional footer. `DeploymentControl`, `SearchControl`, and `ProjectPreviewDialog` all render through this shell now, replacing the prior per-dialog scaffolding under `openpress-deploy-dialog-*` / `openpress-search-dialog-*` / `openpress-project-preview-dialog__*`.
|
|
24
|
+
- **`WorkbenchControlPanel` registry**: `HtmlWorkbench` now accepts an `extraControlPanels?: WorkbenchPanel[]` prop and renders the right-side panel from a `{ id, render }` registry. Built-in panels (pending comments, project entry) ship as the first entries.
|
|
25
|
+
- **Workbench state hooks**: extract `useDeploymentWorkbench` and `useInspectorComments` from `HtmlWorkbench`; `useReaderRuntime` is split into focused sub-hooks (`usePanelState`, `useReaderScrollAnchor`, `useReaderHashSync`, `useReaderKeyboardNav`).
|
|
26
|
+
- **`InlineInspectorLayer` memoization**: now wrapped in `React.memo` with a stable `geometryVersion` prop so the geometry / event listeners no longer rebuild on every parent render.
|
|
27
|
+
- **Panels open lazily**: `usePanelState` now defaults both panels closed, so the reader opens with a clean stage; resize never auto-opens them.
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- Inspector: fix comment-marker count and multi-target marker rendering.
|
|
32
|
+
- Inspector: object-entity id helpers consolidate in `document-model/objectEntityModel` instead of being duplicated inside `Frame`, `MdxArea`, manuscript `TocArea`, and `PublicReaderPage`.
|
|
33
|
+
- Inline editor: `useInlineDocumentEditor` exposes `onDocumentEdited`; `OpenPressApp` re-loads `/openpress/document.json` after a successful inline edit so derived indexes stay in sync.
|
|
34
|
+
- Dev: reset Vite optimizer cache so workspace-side dependencies are picked up.
|
|
35
|
+
- Workbench dialog: viewport-aware width + max-height so a big media preview doesn't blow up the dialog to full screen.
|
|
36
|
+
- Project composer: add `/apply-comments` to the skill mention list so pending comment resolution can be invoked from the workbench.
|
|
37
|
+
- Carries forward the 0.7.1 measurement + pagination fixes (font/image readiness, relative media src inlining, list-per-item paging, `OPENPRESS_DEBUG_ALLOC`, academic-paper starter body overflow).
|
|
38
|
+
|
|
39
|
+
### Breaking Changes
|
|
40
|
+
|
|
41
|
+
- `FrameContext.consumeArea(chainId)` return type changes from `ReactNode | null` to `{ indexInFrame: number; blocks: ReactNode | null }`. Custom `Frame` consumers must read `.blocks`.
|
|
42
|
+
- `App` export is renamed to `OpenPressApp` and now lives under `@open-press/core/app`. The old `renderer.tsx` is replaced by `OpenPressRuntime`.
|
|
43
|
+
- `data-openpress-mdx-area-empty` is now always emitted (`"true"` / `"false"`). Selectors that relied on the attribute being absent need updating.
|
|
44
|
+
- Reader `ViewMode` collapses to `"paged"` only — the legacy `"reading"` flow mode is removed. Use `usePageViewportScale` for free-scaling instead.
|
|
45
|
+
- Several internal module paths moved into subdirectories (`document-model/`, `reader/`, `shared/`, `workbench/...`). Consumers that deep-imported from the openpress source must switch to the new barrels.
|
|
46
|
+
- Shared dialog scaffolding (backdrop, container, header, close button) moved from per-dialog class families (`openpress-deploy-dialog-backdrop`, `__panel`, `__panel header`, `__close`, etc.) to the shared `openpress-workbench-dialog*` family. Per-dialog modifier classes (`openpress-deploy-dialog`, `openpress-search-dialog`, `openpress-project-preview-dialog`) are still applied for dialog-specific styling. Selectors that targeted the old scaffolding names (notably `*-backdrop` and `__panel`) need updating; selectors that combine the modifier class with new `__heading` / `__footer` / `__close` modifiers continue to work.
|
|
47
|
+
|
|
48
|
+
## 0.7.1
|
|
49
|
+
|
|
50
|
+
### Patch Changes
|
|
51
|
+
|
|
52
|
+
- Measurement pipeline + pagination fixes:
|
|
53
|
+
|
|
54
|
+
- **Measurement**: wait on `document.fonts.ready`, image `load`/`error` + `decode()`,
|
|
55
|
+
and two `requestAnimationFrame` ticks before sampling block heights so figures
|
|
56
|
+
no longer under-measure on cold loads.
|
|
57
|
+
- **Measurement**: inline relative `media/`, `./media/`, and `/openpress/media/`
|
|
58
|
+
image sources during the SSR measurement pass (previously only the absolute
|
|
59
|
+
`/openpress/media/...` form was rewritten, leaving relative refs as broken).
|
|
60
|
+
- **MDX compile**: split bullet/numbered lists into per-item paginable blocks
|
|
61
|
+
so long lists can break across pages without losing ordered numbering.
|
|
62
|
+
- **Debug**: new `OPENPRESS_DEBUG_ALLOC` env var prints per-iteration allocator
|
|
63
|
+
state (mdxArea capacities, block heights, pagination hints, warnings).
|
|
64
|
+
- **Academic-paper starter**: `<MdxArea overflow="extend">` on the body and the
|
|
65
|
+
single-column `.reader-page--content .page-body` override removed so content
|
|
66
|
+
paginates naturally with the new allocator.
|
|
67
|
+
|
|
3
68
|
## 0.7.0
|
|
4
69
|
|
|
5
70
|
### Minor Changes
|
|
@@ -16,7 +16,7 @@ export async function run({ root, options }) {
|
|
|
16
16
|
if (!options.noBuild) {
|
|
17
17
|
console.log(`Command: ${formatNodeScriptCommand(root, CLI_ENTRY)} export .`);
|
|
18
18
|
}
|
|
19
|
-
console.log(`Command: npx vite --config vite.config.ts --host ${host} --port ${port}`);
|
|
19
|
+
console.log(`Command: npx vite --force --config vite.config.ts --host ${host} --port ${port}`);
|
|
20
20
|
return 0;
|
|
21
21
|
}
|
|
22
22
|
if (!options.noBuild) {
|
|
@@ -27,7 +27,7 @@ export async function run({ root, options }) {
|
|
|
27
27
|
await printDoctorNoticeIfStale(root);
|
|
28
28
|
|
|
29
29
|
console.log(`OpenPress dev: ${url}`);
|
|
30
|
-
return runCommand("npx", ["vite", "--config", "vite.config.ts", "--host", host, "--port", port], root);
|
|
30
|
+
return runCommand("npx", ["vite", "--force", "--config", "vite.config.ts", "--host", host, "--port", port], root);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
async function printDoctorNoticeIfStale(root) {
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { diagnose } from "./doctor.mjs";
|
|
5
5
|
import { runCommand } from "./_shared.mjs";
|
|
6
6
|
|
|
7
|
+
// Migration notes live in the framework repo, not in scaffolded workspaces.
|
|
8
|
+
// `npx open-press upgrade` fetches the notes for each pending version and
|
|
9
|
+
// caches them under `.openpress/migrations/` so agents can read locally.
|
|
10
|
+
const MIGRATION_REMOTE_BASE = "https://raw.githubusercontent.com/quan0715/open-press/main/docs/migrations";
|
|
11
|
+
const MIGRATION_CACHE_DIR = path.join(".openpress", "migrations");
|
|
12
|
+
|
|
7
13
|
export async function run({ root, options }) {
|
|
8
14
|
const dryRun = Boolean(options?.dryRun);
|
|
9
15
|
const skipSkills = Boolean(options?.noSkills);
|
|
@@ -85,7 +91,11 @@ export async function run({ root, options }) {
|
|
|
85
91
|
process.stdout.write(" (no migration docs in this version range)\n\n");
|
|
86
92
|
} else {
|
|
87
93
|
for (const m of migrationContents) {
|
|
88
|
-
|
|
94
|
+
if (m.path) {
|
|
95
|
+
process.stdout.write(` ─ ${m.path}${m.fetched ? " (fetched from github)" : ""}\n`);
|
|
96
|
+
} else {
|
|
97
|
+
process.stdout.write(` ─ ${m.version}.md (not found locally or on github — check the repo manually)\n`);
|
|
98
|
+
}
|
|
89
99
|
}
|
|
90
100
|
process.stdout.write(
|
|
91
101
|
"\nAgent: open each file, identify document-level changes, grep document/ for affected patterns, propose edits before applying.\n",
|
|
@@ -107,11 +117,43 @@ async function hasCoreDep(root) {
|
|
|
107
117
|
|
|
108
118
|
async function loadMigrations(root, versions) {
|
|
109
119
|
const results = [];
|
|
120
|
+
const cacheDir = path.join(root, MIGRATION_CACHE_DIR);
|
|
121
|
+
await mkdir(cacheDir, { recursive: true });
|
|
122
|
+
|
|
110
123
|
for (const v of versions) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
124
|
+
// Framework repo has docs/migrations/ at root — prefer local if present
|
|
125
|
+
// (covers the open-press framework repo itself acting as a workspace).
|
|
126
|
+
const localDocsPath = path.join(root, "docs", "migrations", `${v}.md`);
|
|
127
|
+
if (existsSync(localDocsPath)) {
|
|
128
|
+
results.push({ version: v, path: path.relative(root, localDocsPath), fetched: false });
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Otherwise fetch from GitHub raw and cache to .openpress/migrations/.
|
|
133
|
+
const cachedPath = path.join(cacheDir, `${v}.md`);
|
|
134
|
+
if (existsSync(cachedPath)) {
|
|
135
|
+
results.push({ version: v, path: path.relative(root, cachedPath), fetched: false });
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const body = await fetchMigration(v);
|
|
140
|
+
if (body) {
|
|
141
|
+
await writeFile(cachedPath, body, "utf8");
|
|
142
|
+
results.push({ version: v, path: path.relative(root, cachedPath), fetched: true });
|
|
143
|
+
} else {
|
|
144
|
+
results.push({ version: v, path: null, fetched: false });
|
|
114
145
|
}
|
|
115
146
|
}
|
|
116
147
|
return results;
|
|
117
148
|
}
|
|
149
|
+
|
|
150
|
+
async function fetchMigration(version) {
|
|
151
|
+
const url = `${MIGRATION_REMOTE_BASE}/${version}.md`;
|
|
152
|
+
try {
|
|
153
|
+
const res = await fetch(url, { headers: { Accept: "text/plain" } });
|
|
154
|
+
if (!res.ok) return null;
|
|
155
|
+
return await res.text();
|
|
156
|
+
} catch {
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -91,6 +91,13 @@ const DEFAULT_PRINT_OPTIONS = {
|
|
|
91
91
|
marginLeft: 0,
|
|
92
92
|
};
|
|
93
93
|
|
|
94
|
+
export const DEFAULT_PRINT_VIEWPORT = Object.freeze({
|
|
95
|
+
width: 1200,
|
|
96
|
+
height: 1698,
|
|
97
|
+
deviceScaleFactor: 1,
|
|
98
|
+
mobile: false,
|
|
99
|
+
});
|
|
100
|
+
|
|
94
101
|
export async function printUrlToPdf({
|
|
95
102
|
root,
|
|
96
103
|
url,
|
|
@@ -98,6 +105,7 @@ export async function printUrlToPdf({
|
|
|
98
105
|
chrome,
|
|
99
106
|
waitForReady = waitForPrintReady,
|
|
100
107
|
printOptions = {},
|
|
108
|
+
viewport = DEFAULT_PRINT_VIEWPORT,
|
|
101
109
|
debuggingPortBase = 9600,
|
|
102
110
|
debuggingPortRange = 300,
|
|
103
111
|
profilePrefix = "chrome-pdf",
|
|
@@ -126,9 +134,7 @@ export async function printUrlToPdf({
|
|
|
126
134
|
const tab = await waitForChromeTab(debuggingPort);
|
|
127
135
|
const client = await connectChromeDevTools(tab.webSocketDebuggerUrl);
|
|
128
136
|
try {
|
|
129
|
-
await client
|
|
130
|
-
await client.send("Runtime.enable");
|
|
131
|
-
await client.send("Emulation.setEmulatedMedia", { media: "print" });
|
|
137
|
+
await preparePdfPage(client, { viewport });
|
|
132
138
|
await client.send("Page.navigate", { url });
|
|
133
139
|
const readyResult = await waitForReady(client);
|
|
134
140
|
const result = await client.send("Page.printToPDF", {
|
|
@@ -146,6 +152,15 @@ export async function printUrlToPdf({
|
|
|
146
152
|
}
|
|
147
153
|
}
|
|
148
154
|
|
|
155
|
+
export async function preparePdfPage(client, { viewport = DEFAULT_PRINT_VIEWPORT } = {}) {
|
|
156
|
+
await client.send("Page.enable");
|
|
157
|
+
await client.send("Runtime.enable");
|
|
158
|
+
if (viewport) {
|
|
159
|
+
await client.send("Emulation.setDeviceMetricsOverride", viewport);
|
|
160
|
+
}
|
|
161
|
+
await client.send("Emulation.setEmulatedMedia", { media: "print" });
|
|
162
|
+
}
|
|
163
|
+
|
|
149
164
|
export async function evaluateUrlWithChrome({
|
|
150
165
|
root,
|
|
151
166
|
url,
|
|
@@ -3,7 +3,9 @@ import http from "node:http";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
import { loadConfig, publicPdfHref } from "../runtime/config.mjs";
|
|
6
|
+
import { searchSourceText } from "../runtime/source-text-tools.mjs";
|
|
6
7
|
import { handleProjectAssetRequest } from "../react/project-asset-endpoint.mjs";
|
|
8
|
+
import { handleSourceEditRequest } from "../react/source-edit-endpoint.mjs";
|
|
7
9
|
|
|
8
10
|
const [rootArg = "dist", ...rest] = process.argv.slice(2);
|
|
9
11
|
const host = valueAfter(rest, "--host") ?? "127.0.0.1";
|
|
@@ -32,6 +34,14 @@ const server = http.createServer(async (req, res) => {
|
|
|
32
34
|
await handleStatusRequest(req, res);
|
|
33
35
|
return;
|
|
34
36
|
}
|
|
37
|
+
if (url.pathname === "/__openpress/search") {
|
|
38
|
+
await handleSearchRequest(req, res, url);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (url.pathname === "/__openpress/source-edit") {
|
|
42
|
+
await handleSourceEditRequest(req, res, { root: workspace });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
35
45
|
if (url.pathname === "/__openpress/local-pdf-export") {
|
|
36
46
|
await handleLocalPdfExportRequest(req, res);
|
|
37
47
|
return;
|
|
@@ -103,6 +113,35 @@ async function handleStatusRequest(req, res) {
|
|
|
103
113
|
});
|
|
104
114
|
}
|
|
105
115
|
|
|
116
|
+
async function handleSearchRequest(req, res, url) {
|
|
117
|
+
if (req.method !== "GET") {
|
|
118
|
+
writeJson(res, 405, { ok: false, message: "Search endpoint requires GET." });
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const query = (url.searchParams.get("q") ?? "").trim();
|
|
123
|
+
if (!query) {
|
|
124
|
+
writeJson(res, 400, { ok: false, message: "Search query is required." });
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const report = await searchSourceText({
|
|
130
|
+
config,
|
|
131
|
+
query,
|
|
132
|
+
scope: searchScopeFrom(url),
|
|
133
|
+
caseSensitive: url.searchParams.get("caseSensitive") === "true",
|
|
134
|
+
});
|
|
135
|
+
writeJson(res, 200, { ok: true, ...report });
|
|
136
|
+
} catch (error) {
|
|
137
|
+
writeJson(res, 500, { ok: false, message: error instanceof Error ? error.message : String(error) });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function searchScopeFrom(url) {
|
|
142
|
+
return url.searchParams.get("scope") === "all" ? "all" : "content";
|
|
143
|
+
}
|
|
144
|
+
|
|
106
145
|
function valueAfter(args, flag) {
|
|
107
146
|
const index = args.indexOf(flag);
|
|
108
147
|
return index >= 0 ? args[index + 1] : undefined;
|
|
@@ -4,8 +4,7 @@ import {
|
|
|
4
4
|
listCommentMarkers,
|
|
5
5
|
updateCommentMarker,
|
|
6
6
|
} from "./comment-marker.mjs";
|
|
7
|
-
|
|
8
|
-
const MAX_COMMENT_BODY_BYTES = 64 * 1024;
|
|
7
|
+
import { readJsonBody, writeJson } from "./http-json.mjs";
|
|
9
8
|
|
|
10
9
|
export async function handleCommentRequest(req, res, {
|
|
11
10
|
root = ".",
|
|
@@ -16,17 +15,14 @@ export async function handleCommentRequest(req, res, {
|
|
|
16
15
|
try {
|
|
17
16
|
writeJson(res, 200, { ok: true, comments: await listCommentMarkers({ root }) });
|
|
18
17
|
} catch (error) {
|
|
19
|
-
|
|
20
|
-
ok: false,
|
|
21
|
-
message: error instanceof Error ? error.message : String(error),
|
|
22
|
-
});
|
|
18
|
+
writeErrorJson(res, error);
|
|
23
19
|
}
|
|
24
20
|
return;
|
|
25
21
|
}
|
|
26
22
|
|
|
27
23
|
if (req.method === "DELETE") {
|
|
28
24
|
try {
|
|
29
|
-
const body = await readJsonBody(req);
|
|
25
|
+
const body = await readJsonBody(req, { bodyLabel: "OpenPress comment request" });
|
|
30
26
|
const result = await clearCommentMarkers({
|
|
31
27
|
root,
|
|
32
28
|
id: body?.id,
|
|
@@ -34,17 +30,14 @@ export async function handleCommentRequest(req, res, {
|
|
|
34
30
|
});
|
|
35
31
|
writeJson(res, 200, { ok: true, ...result });
|
|
36
32
|
} catch (error) {
|
|
37
|
-
|
|
38
|
-
ok: false,
|
|
39
|
-
message: error instanceof Error ? error.message : String(error),
|
|
40
|
-
});
|
|
33
|
+
writeErrorJson(res, error);
|
|
41
34
|
}
|
|
42
35
|
return;
|
|
43
36
|
}
|
|
44
37
|
|
|
45
38
|
if (req.method === "PATCH") {
|
|
46
39
|
try {
|
|
47
|
-
const body = await readJsonBody(req);
|
|
40
|
+
const body = await readJsonBody(req, { bodyLabel: "OpenPress comment request" });
|
|
48
41
|
const result = await updateCommentMarker({
|
|
49
42
|
root,
|
|
50
43
|
id: body?.id,
|
|
@@ -64,10 +57,7 @@ export async function handleCommentRequest(req, res, {
|
|
|
64
57
|
},
|
|
65
58
|
});
|
|
66
59
|
} catch (error) {
|
|
67
|
-
|
|
68
|
-
ok: false,
|
|
69
|
-
message: error instanceof Error ? error.message : String(error),
|
|
70
|
-
});
|
|
60
|
+
writeErrorJson(res, error);
|
|
71
61
|
}
|
|
72
62
|
return;
|
|
73
63
|
}
|
|
@@ -78,7 +68,7 @@ export async function handleCommentRequest(req, res, {
|
|
|
78
68
|
}
|
|
79
69
|
|
|
80
70
|
try {
|
|
81
|
-
const body = await readJsonBody(req);
|
|
71
|
+
const body = await readJsonBody(req, { bodyLabel: "OpenPress comment request" });
|
|
82
72
|
const target = body?.target ?? {};
|
|
83
73
|
const result = await insertCommentMarker({
|
|
84
74
|
root,
|
|
@@ -100,29 +90,13 @@ export async function handleCommentRequest(req, res, {
|
|
|
100
90
|
},
|
|
101
91
|
});
|
|
102
92
|
} catch (error) {
|
|
103
|
-
|
|
104
|
-
ok: false,
|
|
105
|
-
message: error instanceof Error ? error.message : String(error),
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
async function readJsonBody(req) {
|
|
111
|
-
let body = "";
|
|
112
|
-
for await (const chunk of req) {
|
|
113
|
-
body += String(chunk);
|
|
114
|
-
if (Buffer.byteLength(body, "utf8") > MAX_COMMENT_BODY_BYTES) {
|
|
115
|
-
throw new Error("OpenPress comment request body is too large.");
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
try {
|
|
119
|
-
return JSON.parse(body || "{}");
|
|
120
|
-
} catch {
|
|
121
|
-
throw new Error("OpenPress comment request body must be valid JSON.");
|
|
93
|
+
writeErrorJson(res, error);
|
|
122
94
|
}
|
|
123
95
|
}
|
|
124
96
|
|
|
125
|
-
function
|
|
126
|
-
res
|
|
127
|
-
|
|
97
|
+
function writeErrorJson(res, error) {
|
|
98
|
+
writeJson(res, 400, {
|
|
99
|
+
ok: false,
|
|
100
|
+
message: error instanceof Error ? error.message : String(error),
|
|
101
|
+
});
|
|
128
102
|
}
|
|
@@ -14,8 +14,8 @@ const EDITABLE_COMMENT_SOURCE_PATTERNS = [
|
|
|
14
14
|
/^document\/.+\.mdx$/,
|
|
15
15
|
/^document\/.+\.tsx$/,
|
|
16
16
|
];
|
|
17
|
-
const COMMENT_MARKER_RE =
|
|
18
|
-
const COMMENT_LINE_RE = /^\s
|
|
17
|
+
const COMMENT_MARKER_RE = /(?:\{\/\*|\/\*)\s*@openpress-comment\b(?<attrs>[^*]*)\*\/\}?/g;
|
|
18
|
+
const COMMENT_LINE_RE = /^\s*(?:\{\/\*|\/\*)\s*@openpress-comment\b[^*]*\*\/\}?\s*$/;
|
|
19
19
|
|
|
20
20
|
export async function insertCommentMarker({
|
|
21
21
|
root = ".",
|
|
@@ -35,9 +35,15 @@ export async function insertCommentMarker({
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const noteText = normalizedNote(note);
|
|
38
|
-
const marker = createCommentMarker({ id, timestamp, note: noteText, hint });
|
|
39
38
|
const line = normalizeLineNumber(source?.line);
|
|
40
39
|
const text = await fs.readFile(absolutePath, "utf8");
|
|
40
|
+
const marker = createCommentMarker({
|
|
41
|
+
id,
|
|
42
|
+
timestamp,
|
|
43
|
+
note: noteText,
|
|
44
|
+
hint,
|
|
45
|
+
syntax: commentMarkerSyntaxForInsert(text, line, relativePath),
|
|
46
|
+
});
|
|
41
47
|
const nextText = insertLineBefore(text, line, marker);
|
|
42
48
|
await fs.writeFile(absolutePath, nextText, "utf8");
|
|
43
49
|
|
|
@@ -51,9 +57,10 @@ export async function insertCommentMarker({
|
|
|
51
57
|
};
|
|
52
58
|
}
|
|
53
59
|
|
|
54
|
-
export function createCommentMarker({ id = createCommentId(), timestamp = new Date().toISOString(), note, hint } = {}) {
|
|
60
|
+
export function createCommentMarker({ id = createCommentId(), timestamp = new Date().toISOString(), note, hint, syntax = "jsx" } = {}) {
|
|
55
61
|
const payload = { note: normalizedNote(note), ...(typeof hint === "string" && hint.trim() ? { hint: hint.trim() } : {}) };
|
|
56
|
-
|
|
62
|
+
const body = `@openpress-comment id="${escapeMarkerAttribute(id)}" ts="${escapeMarkerAttribute(timestamp)}" text="${encodeCommentPayload(payload)}"`;
|
|
63
|
+
return syntax === "block" ? `/* ${body} */` : `{/* ${body} */}`;
|
|
57
64
|
}
|
|
58
65
|
|
|
59
66
|
export function decodeCommentMarkerText(marker) {
|
|
@@ -285,7 +292,7 @@ function replaceCommentMarkerLine(text, { id, note, hint, timestamp }) {
|
|
|
285
292
|
if (!COMMENT_LINE_RE.test(line)) continue;
|
|
286
293
|
const attrs = parseMarkerAttributes(line);
|
|
287
294
|
if (attrs.id !== id) continue;
|
|
288
|
-
const marker = createCommentMarker({ id, timestamp, note, hint });
|
|
295
|
+
const marker = createCommentMarker({ id, timestamp, note, hint, syntax: commentMarkerSyntaxForLine(line) });
|
|
289
296
|
lines[index] = `${line.match(/^\s*/)?.[0] ?? ""}${marker}`;
|
|
290
297
|
return {
|
|
291
298
|
text: `${lines.join(newline)}${hasTrailingNewline ? newline : ""}`,
|
|
@@ -311,6 +318,23 @@ function parseMarkerAttributes(value) {
|
|
|
311
318
|
return attrs;
|
|
312
319
|
}
|
|
313
320
|
|
|
321
|
+
function commentMarkerSyntaxForInsert(text, line, relativePath) {
|
|
322
|
+
if (!String(relativePath).endsWith(".tsx")) return "jsx";
|
|
323
|
+
const lines = String(text ?? "").split(/\r?\n/);
|
|
324
|
+
const index = Math.min(Math.max(line - 1, 0), lines.length);
|
|
325
|
+
const priorContent = lines.slice(0, index).some((entry) => entry.trim().length > 0);
|
|
326
|
+
if (!priorContent) return "block";
|
|
327
|
+
const targetLine = lines[index] ?? "";
|
|
328
|
+
if (/^\s*(import\b|export\b|function\b|const\b|let\b|var\b|type\b|interface\b|return\b)/.test(targetLine)) {
|
|
329
|
+
return "block";
|
|
330
|
+
}
|
|
331
|
+
return "jsx";
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function commentMarkerSyntaxForLine(line) {
|
|
335
|
+
return /^\s*\/\*/.test(line) ? "block" : "jsx";
|
|
336
|
+
}
|
|
337
|
+
|
|
314
338
|
function lineStartOffsets(text) {
|
|
315
339
|
const starts = [0];
|
|
316
340
|
for (let index = 0; index < text.length; index += 1) {
|
|
@@ -68,6 +68,7 @@ export async function createReactSsrServer(workspaceRoot = ".") {
|
|
|
68
68
|
return createViteServer({
|
|
69
69
|
configFile: false,
|
|
70
70
|
root: FRAMEWORK_ROOT,
|
|
71
|
+
cacheDir: path.join(resolvedWorkspaceRoot, ".openpress", "vite-ssr"),
|
|
71
72
|
appType: "custom",
|
|
72
73
|
logLevel: "silent",
|
|
73
74
|
plugins: [reactRuntimePlugin(), react()],
|
|
@@ -82,6 +83,16 @@ export async function createReactSsrServer(workspaceRoot = ".") {
|
|
|
82
83
|
{ find: "@/components", replacement: path.join(resolvedWorkspaceRoot, "document", "components") },
|
|
83
84
|
],
|
|
84
85
|
},
|
|
86
|
+
optimizeDeps: {
|
|
87
|
+
include: [
|
|
88
|
+
"@mdx-js/react",
|
|
89
|
+
"react",
|
|
90
|
+
"react-dom",
|
|
91
|
+
"react-dom/server",
|
|
92
|
+
"react/jsx-dev-runtime",
|
|
93
|
+
"react/jsx-runtime",
|
|
94
|
+
],
|
|
95
|
+
},
|
|
85
96
|
server: {
|
|
86
97
|
middlewareMode: true,
|
|
87
98
|
fs: {
|