@open-press/core 1.0.0 → 1.1.1
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 +12 -3
- package/engine/cli.mjs +1 -1
- package/engine/commands/_shared.mjs +33 -3
- package/engine/commands/deploy.mjs +3 -3
- package/engine/commands/dev.mjs +13 -4
- package/engine/commands/image.mjs +2 -2
- package/engine/commands/inspect.mjs +3 -2
- package/engine/commands/pdf.mjs +2 -2
- package/engine/commands/preview.mjs +2 -2
- package/engine/commands/render.mjs +6 -4
- package/engine/commands/replace.mjs +1 -1
- package/engine/commands/search.mjs +1 -1
- package/engine/commands/typecheck.mjs +96 -3
- package/engine/output/static-server.mjs +12 -8
- package/index.html +4 -0
- package/package.json +7 -8
- package/src/main.tsx +16 -0
- package/src/openpress/workbench/project/projectSourceModel.ts +2 -2
- package/src/styles/openpress.css +0 -5
- package/src/vite-env.d.ts +8 -0
- package/vite.config.ts +6 -6
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @open-press/core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Package-owned runtime, render engine, and Press Tree primitives for [open-press](https://github.com/quan0715/open-press) — an AI-first fixed-layout document workspace.
|
|
4
4
|
|
|
5
5
|
Most users do **not** install this package directly. Instead, scaffold a workspace with the CLI:
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ Most users do **not** install this package directly. Instead, scaffold a workspa
|
|
|
8
8
|
npx @open-press/cli init my-doc
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
The scaffolded workspace
|
|
11
|
+
The scaffolded workspace depends on this package; it does not vendor a copy of the runtime. Starter files are supplied by skills or by project-specific `press/` source files.
|
|
12
12
|
|
|
13
13
|
## Direct use
|
|
14
14
|
|
|
@@ -36,7 +36,16 @@ import { Sections, Toc } from "@open-press/core/manuscript";
|
|
|
36
36
|
For the maintenance contract around Press Tree, page geometry presets, and the
|
|
37
37
|
allocation pipeline, see [`docs/press-tree.md`](https://github.com/quan0715/open-press/blob/main/docs/press-tree.md).
|
|
38
38
|
|
|
39
|
-
The CLI bin
|
|
39
|
+
The public CLI bin lives in `@open-press/cli` and delegates runtime commands to this package:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install @open-press/core @open-press/cli
|
|
43
|
+
npx open-press dev .
|
|
44
|
+
npx open-press render .
|
|
45
|
+
npx open-press pdf .
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`@open-press/core` owns the internal browser shell (`index.html`), Vite config, React app runtime, render pipeline, and static server. A workspace owns `press/`, `package.json`, media, components, and theme files.
|
|
40
49
|
|
|
41
50
|
## License
|
|
42
51
|
|
package/engine/cli.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawn, spawnSync } from "node:child_process";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
import fs from "node:fs/promises";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
@@ -8,8 +9,14 @@ import { exportDocument } from "../document-export.mjs";
|
|
|
8
9
|
import { optimizePdfMediaForStaticRoot } from "../output/pdf-media.mjs";
|
|
9
10
|
|
|
10
11
|
export const ENGINE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
12
|
+
export const FRAMEWORK_ROOT = path.resolve(ENGINE_DIR, "..");
|
|
11
13
|
export const CLI_ENTRY = path.join(ENGINE_DIR, "cli.mjs");
|
|
12
14
|
export const STATIC_SERVER = path.join(ENGINE_DIR, "output", "static-server.mjs");
|
|
15
|
+
export const VITE_CONFIG = path.join(FRAMEWORK_ROOT, "vite.config.ts");
|
|
16
|
+
|
|
17
|
+
const require = createRequire(import.meta.url);
|
|
18
|
+
const VITE_PACKAGE_JSON = require.resolve("vite/package.json");
|
|
19
|
+
export const VITE_BIN = path.join(path.dirname(VITE_PACKAGE_JSON), "bin", "vite.js");
|
|
13
20
|
|
|
14
21
|
export function parseOptions(argv) {
|
|
15
22
|
const options = {};
|
|
@@ -47,8 +54,12 @@ export function formatDisplayPath(absolutePath) {
|
|
|
47
54
|
return relative;
|
|
48
55
|
}
|
|
49
56
|
|
|
50
|
-
export function runCommand(commandName, commandArgs, cwd) {
|
|
51
|
-
const result = spawnSync(commandName, commandArgs, {
|
|
57
|
+
export function runCommand(commandName, commandArgs, cwd, opts = {}) {
|
|
58
|
+
const result = spawnSync(commandName, commandArgs, {
|
|
59
|
+
cwd,
|
|
60
|
+
env: { ...process.env, ...(opts.env ?? {}) },
|
|
61
|
+
stdio: "inherit",
|
|
62
|
+
});
|
|
52
63
|
return result.status ?? 1;
|
|
53
64
|
}
|
|
54
65
|
|
|
@@ -58,6 +69,24 @@ export function formatNodeScriptCommand(root, scriptPath) {
|
|
|
58
69
|
return `node ${displayPath}`;
|
|
59
70
|
}
|
|
60
71
|
|
|
72
|
+
export function formatOpenPressCommand(args = []) {
|
|
73
|
+
return `open-press ${args.join(" ")}`.trim();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function workspaceRuntimeEnv(root) {
|
|
77
|
+
return { OPENPRESS_WORKSPACE_ROOT: path.resolve(root) };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function viteCommandArgs(args = []) {
|
|
81
|
+
return [VITE_BIN, ...args];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function formatViteCommand(root, args = []) {
|
|
85
|
+
const script = formatNodeScriptCommand(root, VITE_BIN);
|
|
86
|
+
const config = formatDisplayPath(VITE_CONFIG);
|
|
87
|
+
return `${script} ${args.join(" ")} --config ${config}`.replace(/\s+/g, " ").trim();
|
|
88
|
+
}
|
|
89
|
+
|
|
61
90
|
export async function buildReactStatic({ root, noBuild = false, recurse, silent = false }) {
|
|
62
91
|
if (noBuild) return 0;
|
|
63
92
|
if (!silent) {
|
|
@@ -65,9 +94,10 @@ export async function buildReactStatic({ root, noBuild = false, recurse, silent
|
|
|
65
94
|
}
|
|
66
95
|
|
|
67
96
|
await exportDocument(root);
|
|
68
|
-
const result = spawnSync("
|
|
97
|
+
const result = spawnSync("node", viteCommandArgs(["build", "--config", VITE_CONFIG]), {
|
|
69
98
|
cwd: root,
|
|
70
99
|
encoding: "utf8",
|
|
100
|
+
env: { ...process.env, ...workspaceRuntimeEnv(root) },
|
|
71
101
|
});
|
|
72
102
|
return result.status ?? 1;
|
|
73
103
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { deploySync } from "../output/deploy-sync.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { buildReactPdf, formatOpenPressCommand, runCommand, writePdfStageDeployConfig } from "./_shared.mjs";
|
|
4
4
|
|
|
5
5
|
export async function run({ root, config, options, recurse }) {
|
|
6
6
|
if (config.deploy.requiresConfirmation === true && !options.confirm) {
|
|
@@ -12,9 +12,9 @@ export async function run({ root, config, options, recurse }) {
|
|
|
12
12
|
const commitDirty = config.deploy.commitDirty;
|
|
13
13
|
if (options.dryRun) {
|
|
14
14
|
console.log("OpenPress deploy dry run");
|
|
15
|
-
console.log(`Command: ${
|
|
15
|
+
console.log(`Command: ${formatOpenPressCommand(["render", ".", "--renderer", "react"])}`);
|
|
16
16
|
console.log(`Step: deploy-sync (copy ${config.outputDir} → ${source})`);
|
|
17
|
-
console.log(`Command: ${
|
|
17
|
+
console.log(`Command: ${formatOpenPressCommand(["pdf", ".", "--output", `${source}/${config.pdf.filename}`])}`);
|
|
18
18
|
console.log(`Step: write ${source}/openpress/deploy.json with deployment metadata`);
|
|
19
19
|
console.log(`Command: npx wrangler pages deploy ${source}${projectName ? ` --project-name=${projectName}` : ""}${commitDirty ? " --commit-dirty=true" : ""}`);
|
|
20
20
|
return 0;
|
package/engine/commands/dev.mjs
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import { exportDocument } from "../document-export.mjs";
|
|
2
2
|
import { diagnose } from "./doctor.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
VITE_CONFIG,
|
|
5
|
+
formatOpenPressCommand,
|
|
6
|
+
formatViteCommand,
|
|
7
|
+
runCommand,
|
|
8
|
+
viteCommandArgs,
|
|
9
|
+
workspaceRuntimeEnv,
|
|
10
|
+
} from "./_shared.mjs";
|
|
4
11
|
|
|
5
12
|
export async function run({ root, options }) {
|
|
6
13
|
const renderer = options.renderer ?? "react";
|
|
@@ -14,9 +21,9 @@ export async function run({ root, options }) {
|
|
|
14
21
|
if (options.dryRun) {
|
|
15
22
|
console.log(`OpenPress dev URL: ${url}`);
|
|
16
23
|
if (!options.noBuild) {
|
|
17
|
-
console.log(`Command: ${
|
|
24
|
+
console.log(`Command: ${formatOpenPressCommand(["export", "."])}`);
|
|
18
25
|
}
|
|
19
|
-
console.log(`Command:
|
|
26
|
+
console.log(`Command: ${formatViteCommand(root, ["--force", "--host", host, "--port", port])}`);
|
|
20
27
|
return 0;
|
|
21
28
|
}
|
|
22
29
|
if (!options.noBuild) {
|
|
@@ -27,7 +34,9 @@ export async function run({ root, options }) {
|
|
|
27
34
|
await printDoctorNoticeIfStale(root);
|
|
28
35
|
|
|
29
36
|
console.log(`OpenPress dev: ${url}`);
|
|
30
|
-
return runCommand("
|
|
37
|
+
return runCommand("node", viteCommandArgs(["--force", "--config", VITE_CONFIG, "--host", host, "--port", port]), root, {
|
|
38
|
+
env: workspaceRuntimeEnv(root),
|
|
39
|
+
});
|
|
31
40
|
}
|
|
32
41
|
|
|
33
42
|
async function printDoctorNoticeIfStale(root) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import {
|
|
2
|
+
import { STATIC_SERVER, buildReactImages, formatNodeScriptCommand, formatOpenPressCommand } from "./_shared.mjs";
|
|
3
3
|
|
|
4
4
|
export async function run({ root, config, options, recurse }) {
|
|
5
5
|
const outputDir = options.output ? path.resolve(root, options.output) : path.join(config.paths.outputDir, "images");
|
|
@@ -7,7 +7,7 @@ export async function run({ root, config, options, recurse }) {
|
|
|
7
7
|
const port = options.port ?? "5186";
|
|
8
8
|
|
|
9
9
|
if (options.dryRun) {
|
|
10
|
-
console.log(`Command: ${
|
|
10
|
+
console.log(`Command: ${formatOpenPressCommand(["render", ".", "--renderer", "react"])}`);
|
|
11
11
|
console.log(`Command: ${formatNodeScriptCommand(root, STATIC_SERVER)} ${config.outputDir} --host ${host} --port ${port} --workspace .`);
|
|
12
12
|
console.log(`Chrome image export URL: http://${host}:${port}/?print=1`);
|
|
13
13
|
console.log(`Output: ${path.relative(root, path.join(outputDir, "page-001.png"))}`);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { inspectWorkspace } from "../runtime/inspection.mjs";
|
|
2
2
|
import { exitCodeForIssueReport } from "../runtime/issue-report.mjs";
|
|
3
|
+
import { STATIC_SERVER, formatNodeScriptCommand, formatOpenPressCommand } from "./_shared.mjs";
|
|
3
4
|
|
|
4
5
|
export async function run({ root, config, options, recurse }) {
|
|
5
6
|
const host = options.host ?? "127.0.0.1";
|
|
@@ -8,9 +9,9 @@ export async function run({ root, config, options, recurse }) {
|
|
|
8
9
|
|
|
9
10
|
if (options.dryRun) {
|
|
10
11
|
if (!options.noBuild) {
|
|
11
|
-
console.log(
|
|
12
|
+
console.log(`Command: ${formatOpenPressCommand(["render", ".", "--renderer", "react"])}`);
|
|
12
13
|
}
|
|
13
|
-
console.log(`Command:
|
|
14
|
+
console.log(`Command: ${formatNodeScriptCommand(root, STATIC_SERVER)} ${config.outputDir} --host ${host} --port ${port} --workspace .`);
|
|
14
15
|
console.log(`Chrome inspection URL: ${url}`);
|
|
15
16
|
return 0;
|
|
16
17
|
}
|
package/engine/commands/pdf.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import {
|
|
2
|
+
import { STATIC_SERVER, buildReactPdf, formatNodeScriptCommand, formatOpenPressCommand } from "./_shared.mjs";
|
|
3
3
|
|
|
4
4
|
export async function run({ root, config, options, recurse }) {
|
|
5
5
|
const outputPath = options.output ? path.resolve(root, options.output) : undefined;
|
|
@@ -7,7 +7,7 @@ export async function run({ root, config, options, recurse }) {
|
|
|
7
7
|
const relOutput = path.relative(root, outputPath ?? config.paths.pdf);
|
|
8
8
|
const host = options.host ?? "127.0.0.1";
|
|
9
9
|
const port = options.port ?? "5185";
|
|
10
|
-
console.log(`Command: ${
|
|
10
|
+
console.log(`Command: ${formatOpenPressCommand(["render", ".", "--renderer", "react"])}`);
|
|
11
11
|
console.log(`Command: ${formatNodeScriptCommand(root, STATIC_SERVER)} ${config.outputDir} --host ${host} --port ${port} --workspace .`);
|
|
12
12
|
console.log(`Command: Chrome --print-to-pdf=${relOutput} http://${host}:${port}/?print=1`);
|
|
13
13
|
return 0;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { STATIC_SERVER, formatNodeScriptCommand, formatOpenPressCommand, runCommand } from "./_shared.mjs";
|
|
2
2
|
|
|
3
3
|
export async function run({ root, config, options, recurse }) {
|
|
4
4
|
const renderer = options.renderer ?? "react";
|
|
@@ -12,7 +12,7 @@ export async function run({ root, config, options, recurse }) {
|
|
|
12
12
|
if (options.dryRun) {
|
|
13
13
|
console.log(`OpenPress preview URL: ${url}`);
|
|
14
14
|
if (!options.noBuild) {
|
|
15
|
-
console.log(`Command: ${
|
|
15
|
+
console.log(`Command: ${formatOpenPressCommand(["render", ".", "--renderer", "react"])}`);
|
|
16
16
|
}
|
|
17
17
|
console.log(`Command: ${formatNodeScriptCommand(root, STATIC_SERVER)} ${config.outputDir} --host ${host} --port ${port} --workspace .`);
|
|
18
18
|
return 0;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { exportDocument } from "../document-export.mjs";
|
|
2
|
-
import { runCommand } from "./_shared.mjs";
|
|
2
|
+
import { VITE_CONFIG, formatOpenPressCommand, formatViteCommand, runCommand, viteCommandArgs, workspaceRuntimeEnv } from "./_shared.mjs";
|
|
3
3
|
|
|
4
4
|
export async function run({ root, options }) {
|
|
5
5
|
const renderer = options.renderer ?? "react";
|
|
@@ -8,10 +8,12 @@ export async function run({ root, options }) {
|
|
|
8
8
|
return 2;
|
|
9
9
|
}
|
|
10
10
|
if (options.dryRun) {
|
|
11
|
-
console.log(
|
|
12
|
-
console.log(
|
|
11
|
+
console.log(`Command: ${formatOpenPressCommand(["export", "."])}`);
|
|
12
|
+
console.log(`Command: ${formatViteCommand(root, ["build"])}`);
|
|
13
13
|
return 0;
|
|
14
14
|
}
|
|
15
15
|
await exportDocument(root);
|
|
16
|
-
return runCommand("
|
|
16
|
+
return runCommand("node", viteCommandArgs(["build", "--config", VITE_CONFIG]), root, {
|
|
17
|
+
env: workspaceRuntimeEnv(root),
|
|
18
|
+
});
|
|
17
19
|
}
|
|
@@ -3,7 +3,7 @@ import { replaceSourceText } from "../runtime/source-text-tools.mjs";
|
|
|
3
3
|
export async function run({ config, options }) {
|
|
4
4
|
const args = replaceArgsFromOptions(options);
|
|
5
5
|
if (!args) {
|
|
6
|
-
console.error("Usage:
|
|
6
|
+
console.error("Usage: open-press replace [path] <from> <to> [--json] [--apply] [--scope content|all] [--include-code] [--case-sensitive]");
|
|
7
7
|
return 2;
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ import { searchSourceText } from "../runtime/source-text-tools.mjs";
|
|
|
3
3
|
export async function run({ config, options }) {
|
|
4
4
|
const query = searchQueryFromOptions(options);
|
|
5
5
|
if (!query) {
|
|
6
|
-
console.error("Usage:
|
|
6
|
+
console.error("Usage: open-press search [path] <query> [--json] [--scope content|all] [--case-sensitive]");
|
|
7
7
|
return 2;
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { createRequire } from "node:module";
|
|
4
|
-
import { runCommand } from "./_shared.mjs";
|
|
5
|
+
import { FRAMEWORK_ROOT, runCommand } from "./_shared.mjs";
|
|
6
|
+
import { loadConfig } from "../runtime/config.mjs";
|
|
5
7
|
|
|
6
8
|
// Run typecheck via the locally installed typescript. The previous
|
|
7
9
|
// implementation used `npx tsc`; npm 11 + Node 24 (our CI / release
|
|
@@ -17,14 +19,15 @@ import { runCommand } from "./_shared.mjs";
|
|
|
17
19
|
// even when bare require.resolve doesn't, which is what CI hits.
|
|
18
20
|
export async function run({ root }) {
|
|
19
21
|
const absoluteRoot = path.resolve(root);
|
|
22
|
+
const projectPath = await resolveTypecheckProject(absoluteRoot);
|
|
20
23
|
|
|
21
24
|
const tscBin = resolveTscBin(absoluteRoot);
|
|
22
25
|
if (tscBin) {
|
|
23
|
-
return runCommand("node", [tscBin, "--noEmit", "-p",
|
|
26
|
+
return runCommand("node", [tscBin, "--noEmit", "-p", projectPath], absoluteRoot);
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
if (hasCommand("pnpm")) {
|
|
27
|
-
return runCommand("pnpm", ["exec", "tsc", "--noEmit", "-p",
|
|
30
|
+
return runCommand("pnpm", ["exec", "tsc", "--noEmit", "-p", projectPath], absoluteRoot);
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
console.error("[openpress] typescript is not installed in this workspace.");
|
|
@@ -32,6 +35,88 @@ export async function run({ root }) {
|
|
|
32
35
|
return 1;
|
|
33
36
|
}
|
|
34
37
|
|
|
38
|
+
async function resolveTypecheckProject(absoluteRoot) {
|
|
39
|
+
const workspaceProject = path.join(absoluteRoot, "tsconfig.json");
|
|
40
|
+
if (fs.existsSync(workspaceProject)) return workspaceProject;
|
|
41
|
+
return await writeGeneratedTypecheckProject(absoluteRoot);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function writeGeneratedTypecheckProject(absoluteRoot) {
|
|
45
|
+
const config = await loadConfig(absoluteRoot);
|
|
46
|
+
const outDir = path.join(absoluteRoot, ".openpress");
|
|
47
|
+
await mkdir(outDir, { recursive: true });
|
|
48
|
+
|
|
49
|
+
const projectPath = path.join(outDir, "typecheck.tsconfig.json");
|
|
50
|
+
const fromProjectDir = (target) => normalizePath(path.relative(outDir, target)) || ".";
|
|
51
|
+
const fromWorkspace = (target) => normalizePath(path.relative(absoluteRoot, target)) || ".";
|
|
52
|
+
const includeRoot = (target) => {
|
|
53
|
+
const relative = fromProjectDir(target);
|
|
54
|
+
return relative === "." ? "." : relative;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const typeRoots = [
|
|
58
|
+
path.join(absoluteRoot, "node_modules", "@types"),
|
|
59
|
+
path.join(FRAMEWORK_ROOT, "node_modules", "@types"),
|
|
60
|
+
]
|
|
61
|
+
.filter((dir) => fs.existsSync(dir))
|
|
62
|
+
.map((dir) => fromProjectDir(dir));
|
|
63
|
+
|
|
64
|
+
const typecheckConfig = {
|
|
65
|
+
compilerOptions: {
|
|
66
|
+
target: "ES2022",
|
|
67
|
+
useDefineForClassFields: true,
|
|
68
|
+
lib: ["DOM", "DOM.Iterable", "ES2022"],
|
|
69
|
+
allowJs: false,
|
|
70
|
+
skipLibCheck: true,
|
|
71
|
+
esModuleInterop: true,
|
|
72
|
+
allowSyntheticDefaultImports: true,
|
|
73
|
+
strict: true,
|
|
74
|
+
forceConsistentCasingInFileNames: true,
|
|
75
|
+
module: "ESNext",
|
|
76
|
+
moduleResolution: "Bundler",
|
|
77
|
+
types: ["node"],
|
|
78
|
+
...(typeRoots.length > 0 ? { typeRoots } : {}),
|
|
79
|
+
resolveJsonModule: true,
|
|
80
|
+
isolatedModules: true,
|
|
81
|
+
noEmit: true,
|
|
82
|
+
jsx: "react-jsx",
|
|
83
|
+
ignoreDeprecations: "6.0",
|
|
84
|
+
baseUrl: "..",
|
|
85
|
+
paths: {
|
|
86
|
+
"@open-press/core": [fromWorkspace(path.join(FRAMEWORK_ROOT, "src", "openpress", "core", "index.tsx"))],
|
|
87
|
+
"@open-press/core/mdx": [fromWorkspace(path.join(FRAMEWORK_ROOT, "src", "openpress", "mdx", "index.ts"))],
|
|
88
|
+
"@open-press/core/manuscript": [fromWorkspace(path.join(FRAMEWORK_ROOT, "src", "openpress", "manuscript", "index.tsx"))],
|
|
89
|
+
"@open-press/core/numbering": [fromWorkspace(path.join(FRAMEWORK_ROOT, "src", "openpress", "numbering", "index.ts"))],
|
|
90
|
+
"@/components": [
|
|
91
|
+
`${fromWorkspace(config.paths.componentsDir)}/index.ts`,
|
|
92
|
+
`${fromWorkspace(config.paths.componentsDir)}/index.tsx`,
|
|
93
|
+
],
|
|
94
|
+
"@/components/*": [`${fromWorkspace(config.paths.componentsDir)}/*`],
|
|
95
|
+
"@workspace/content": [fromWorkspace(config.paths.sourceDir)],
|
|
96
|
+
"@workspace/content/*": [`${fromWorkspace(config.paths.sourceDir)}/*`],
|
|
97
|
+
"@workspace/media": [fromWorkspace(config.paths.mediaDir)],
|
|
98
|
+
"@workspace/media/*": [`${fromWorkspace(config.paths.mediaDir)}/*`],
|
|
99
|
+
"@workspace/components": [fromWorkspace(config.paths.componentsDir)],
|
|
100
|
+
"@workspace/components/*": [`${fromWorkspace(config.paths.componentsDir)}/*`],
|
|
101
|
+
"@/*": [`${fromWorkspace(path.join(FRAMEWORK_ROOT, "src"))}/*`],
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
include: [
|
|
105
|
+
`${includeRoot(config.paths.documentRoot)}/**/*.ts`,
|
|
106
|
+
`${includeRoot(config.paths.documentRoot)}/**/*.tsx`,
|
|
107
|
+
"../tests/**/*.test.ts",
|
|
108
|
+
"../tests/**/*.test.tsx",
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
await writeFile(projectPath, `${JSON.stringify(typecheckConfig, null, 2)}\n`, "utf8");
|
|
113
|
+
return projectPath;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function normalizePath(value) {
|
|
117
|
+
return value.replaceAll("\\", "/");
|
|
118
|
+
}
|
|
119
|
+
|
|
35
120
|
function resolveTscBin(absoluteRoot) {
|
|
36
121
|
try {
|
|
37
122
|
const require = createRequire(path.join(absoluteRoot, "package.json"));
|
|
@@ -41,6 +126,14 @@ function resolveTscBin(absoluteRoot) {
|
|
|
41
126
|
// fall through to .bin probe
|
|
42
127
|
}
|
|
43
128
|
|
|
129
|
+
try {
|
|
130
|
+
const require = createRequire(import.meta.url);
|
|
131
|
+
const pkgPath = require.resolve("typescript/package.json");
|
|
132
|
+
return path.join(path.dirname(pkgPath), "bin", "tsc");
|
|
133
|
+
} catch {
|
|
134
|
+
// fall through to .bin probe
|
|
135
|
+
}
|
|
136
|
+
|
|
44
137
|
let dir = absoluteRoot;
|
|
45
138
|
while (true) {
|
|
46
139
|
const candidate = path.join(dir, "node_modules", ".bin", "tsc");
|
|
@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
|
|
|
2
2
|
import http from "node:http";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { loadConfig, publicPdfHref } from "../runtime/config.mjs";
|
|
6
7
|
import { searchSourceText } from "../runtime/source-text-tools.mjs";
|
|
7
8
|
import { handleProjectAssetRequest } from "../react/project-asset-endpoint.mjs";
|
|
@@ -13,6 +14,9 @@ const port = Number(valueAfter(rest, "--port") ?? "8765");
|
|
|
13
14
|
const root = path.resolve(rootArg);
|
|
14
15
|
const workspace = path.resolve(valueAfter(rest, "--workspace") ?? await inferWorkspaceRoot(root));
|
|
15
16
|
const config = await loadConfig(workspace);
|
|
17
|
+
const ENGINE_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
18
|
+
const FRAMEWORK_ROOT = path.resolve(ENGINE_DIR, "..");
|
|
19
|
+
const CLI_ENTRY = path.join(ENGINE_DIR, "cli.mjs");
|
|
16
20
|
|
|
17
21
|
const mimeTypes = {
|
|
18
22
|
".html": "text/html; charset=utf-8",
|
|
@@ -210,7 +214,7 @@ async function handleLocalPdfExportRequest(req, res) {
|
|
|
210
214
|
ok: result.code === 0 && exists,
|
|
211
215
|
code: result.code,
|
|
212
216
|
pdf: `/__openpress/local-pdf-file?ts=${Date.now()}`,
|
|
213
|
-
command: "
|
|
217
|
+
command: "open-press pdf .",
|
|
214
218
|
stdout: result.stdout,
|
|
215
219
|
stderr: result.stderr,
|
|
216
220
|
});
|
|
@@ -250,7 +254,7 @@ async function handleDeployRequest(req, res) {
|
|
|
250
254
|
deploy_adapter: config.deploy.adapter,
|
|
251
255
|
deploy_source: config.deploy.source,
|
|
252
256
|
deploy_project_name: config.deploy.projectName,
|
|
253
|
-
command: "
|
|
257
|
+
command: "open-press deploy . --confirm",
|
|
254
258
|
});
|
|
255
259
|
return;
|
|
256
260
|
}
|
|
@@ -269,7 +273,7 @@ async function handleDeployRequest(req, res) {
|
|
|
269
273
|
pdf: deployedUrl ? `${deployedUrl}/${config.pdf.filename}` : deploymentInfo.pdf,
|
|
270
274
|
public_url: publicUrl,
|
|
271
275
|
dirty: false,
|
|
272
|
-
command: "
|
|
276
|
+
command: "open-press deploy . --confirm",
|
|
273
277
|
stdout: result.stdout,
|
|
274
278
|
stderr: result.stderr,
|
|
275
279
|
});
|
|
@@ -354,7 +358,7 @@ async function handleMediaFileRequest(req, res, url) {
|
|
|
354
358
|
|
|
355
359
|
function runLocalPdfExport() {
|
|
356
360
|
return new Promise((resolve) => {
|
|
357
|
-
const child = spawn("node", [
|
|
361
|
+
const child = spawn("node", [CLI_ENTRY, "pdf", "."], {
|
|
358
362
|
cwd: workspace,
|
|
359
363
|
shell: false,
|
|
360
364
|
});
|
|
@@ -377,7 +381,7 @@ function runLocalPdfExport() {
|
|
|
377
381
|
|
|
378
382
|
function runDeploy() {
|
|
379
383
|
return new Promise((resolve) => {
|
|
380
|
-
const child = spawn("node", [
|
|
384
|
+
const child = spawn("node", [CLI_ENTRY, "deploy", ".", "--confirm"], {
|
|
381
385
|
cwd: workspace,
|
|
382
386
|
shell: false,
|
|
383
387
|
});
|
|
@@ -471,10 +475,10 @@ function getDeploymentSourcePaths() {
|
|
|
471
475
|
config.paths.themeDir,
|
|
472
476
|
config.paths.designDoc,
|
|
473
477
|
config.paths.componentsDir,
|
|
474
|
-
path.join(
|
|
475
|
-
path.join(
|
|
478
|
+
path.join(FRAMEWORK_ROOT, "src"),
|
|
479
|
+
path.join(FRAMEWORK_ROOT, "index.html"),
|
|
480
|
+
path.join(FRAMEWORK_ROOT, "vite.config.ts"),
|
|
476
481
|
path.join(workspace, "package.json"),
|
|
477
|
-
path.join(workspace, "vite.config.ts"),
|
|
478
482
|
];
|
|
479
483
|
}
|
|
480
484
|
|
package/index.html
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
|
|
7
|
+
<link rel="stylesheet" href="/openpress/fonts.css" />
|
|
8
|
+
<link rel="stylesheet" href="/openpress/tokens.css" />
|
|
9
|
+
<link rel="stylesheet" href="/openpress/content.css" />
|
|
10
|
+
<link rel="stylesheet" href="/openpress/components.css" />
|
|
7
11
|
<title>OpenPress Workspace</title>
|
|
8
12
|
</head>
|
|
9
13
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-press/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "open-press core — runtime primitives, CLI, and render pipeline for AI-first fixed-layout documents.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,13 +31,12 @@
|
|
|
31
31
|
"./manuscript": "./src/openpress/manuscript/index.tsx",
|
|
32
32
|
"./numbering": "./src/openpress/numbering/index.ts"
|
|
33
33
|
},
|
|
34
|
-
"bin": {
|
|
35
|
-
"open-press": "engine/cli.mjs"
|
|
36
|
-
},
|
|
37
34
|
"files": [
|
|
38
35
|
"engine",
|
|
36
|
+
"src/main.tsx",
|
|
39
37
|
"src/openpress",
|
|
40
38
|
"src/styles",
|
|
39
|
+
"src/vite-env.d.ts",
|
|
41
40
|
"index.html",
|
|
42
41
|
"vite.config.ts",
|
|
43
42
|
"tsconfig.json"
|
|
@@ -52,13 +51,16 @@
|
|
|
52
51
|
"js-yaml": "^4.1.1",
|
|
53
52
|
"katex": "^0.16.47",
|
|
54
53
|
"lucide-react": "^1.16.0",
|
|
54
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
55
55
|
"playwright": "^1.60.0",
|
|
56
56
|
"postcss": "^8.5.6",
|
|
57
57
|
"react": "^19.2.6",
|
|
58
58
|
"react-dom": "^19.2.6",
|
|
59
59
|
"rehype-katex": "^7.0.1",
|
|
60
60
|
"remark-gfm": "^4.0.1",
|
|
61
|
-
"remark-math": "^6.0.0"
|
|
61
|
+
"remark-math": "^6.0.0",
|
|
62
|
+
"typescript": "^6.0.3",
|
|
63
|
+
"vite": "^8.0.13"
|
|
62
64
|
},
|
|
63
65
|
"devDependencies": {
|
|
64
66
|
"@playwright/test": "^1.60.0",
|
|
@@ -66,10 +68,7 @@
|
|
|
66
68
|
"@types/node": "^25.8.0",
|
|
67
69
|
"@types/react": "^19.2.14",
|
|
68
70
|
"@types/react-dom": "^19.2.3",
|
|
69
|
-
"@vitejs/plugin-react": "^6.0.2",
|
|
70
71
|
"jsdom": "^26.1.0",
|
|
71
|
-
"typescript": "^6.0.3",
|
|
72
|
-
"vite": "^8.0.13",
|
|
73
72
|
"vitest": "^4.1.6"
|
|
74
73
|
},
|
|
75
74
|
"scripts": {
|
package/src/main.tsx
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { StrictMode } from "react";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
import { OpenPressApp } from "./openpress/app";
|
|
4
|
+
import "./styles/openpress.css";
|
|
5
|
+
|
|
6
|
+
const rootElement = document.getElementById("root");
|
|
7
|
+
|
|
8
|
+
if (!rootElement) {
|
|
9
|
+
throw new Error("OpenPress renderer requires a #root element.");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
createRoot(rootElement).render(
|
|
13
|
+
<StrictMode>
|
|
14
|
+
<OpenPressApp />
|
|
15
|
+
</StrictMode>,
|
|
16
|
+
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// Source directory paths come from
|
|
2
|
-
//
|
|
1
|
+
// Source directory paths come from package-owned Vite build-time defines,
|
|
2
|
+
// which read the active workspace conventions and package.json config.
|
|
3
3
|
|
|
4
4
|
export const PROJECT_SOURCES = {
|
|
5
5
|
content: {
|
package/src/styles/openpress.css
CHANGED
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
@import url("/openpress/fonts.css");
|
|
2
|
-
@import url("/openpress/tokens.css");
|
|
3
|
-
@import url("/openpress/content.css");
|
|
4
|
-
@import url("/openpress/components.css");
|
|
5
|
-
|
|
6
1
|
@import "./openpress/app-shell.css";
|
|
7
2
|
@import "./openpress/workspace-gallery.css";
|
|
8
3
|
@import "./openpress/workbench.css";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
|
|
3
|
+
// Workspace path constants injected by vite.config.ts at build time.
|
|
4
|
+
// These come from package-owned workspace conventions and package.json config.
|
|
5
|
+
declare const __OPENPRESS_CONTENT_PATH__: string;
|
|
6
|
+
declare const __OPENPRESS_MEDIA_PATH__: string;
|
|
7
|
+
declare const __OPENPRESS_COMPONENTS_PATH__: string;
|
|
8
|
+
declare const __OPENPRESS_PDF_HREF__: string;
|
package/vite.config.ts
CHANGED
|
@@ -54,8 +54,10 @@ const workspaceDefines = {
|
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
export default defineConfig({
|
|
57
|
+
root: frameworkRoot,
|
|
57
58
|
base: "./",
|
|
58
59
|
cacheDir: path.join(workspaceRoot, ".openpress", "vite-client"),
|
|
60
|
+
publicDir: path.join(workspaceRoot, "public"),
|
|
59
61
|
plugins: [openpressLocalDeployPlugin(), react()],
|
|
60
62
|
define: workspaceDefines,
|
|
61
63
|
resolve: {
|
|
@@ -409,7 +411,7 @@ function isLocalDeployConfigured() {
|
|
|
409
411
|
function localDeploySetupMessage() {
|
|
410
412
|
if (isLocalDeployConfigured()) return undefined;
|
|
411
413
|
if (openpressConfig.deploy.adapter === "cloudflare-pages") {
|
|
412
|
-
return "Cloudflare Pages deployment requires `deploy.projectName` in
|
|
414
|
+
return "Cloudflare Pages deployment requires `openpress.deploy.projectName` in package.json.";
|
|
413
415
|
}
|
|
414
416
|
return `Deployment adapter \`${openpressConfig.deploy.adapter}\` is not configured.`;
|
|
415
417
|
}
|
|
@@ -472,18 +474,16 @@ function getLocalDeploymentSourcePaths() {
|
|
|
472
474
|
openpressConfig.paths.designDoc,
|
|
473
475
|
openpressConfig.paths.componentsDir,
|
|
474
476
|
path.join(frameworkRoot, "src"),
|
|
475
|
-
path.join(
|
|
477
|
+
path.join(frameworkRoot, "index.html"),
|
|
478
|
+
path.join(frameworkRoot, "vite.config.ts"),
|
|
476
479
|
path.join(workspaceRoot, "package.json"),
|
|
477
480
|
path.join(workspaceRoot, "openpress.config.mjs"),
|
|
478
481
|
openpressConfig.configPath,
|
|
479
|
-
path.join(workspaceRoot, "vite.config.ts"),
|
|
480
482
|
];
|
|
481
483
|
}
|
|
482
484
|
|
|
483
485
|
function openpressCliCommand(args: string[]) {
|
|
484
|
-
|
|
485
|
-
const displayCliPath = relativeCliPath && !relativeCliPath.startsWith("../") ? relativeCliPath : openpressCliPath;
|
|
486
|
-
return `node ${displayCliPath} ${args.join(" ")}`;
|
|
486
|
+
return `open-press ${args.join(" ")}`;
|
|
487
487
|
}
|
|
488
488
|
|
|
489
489
|
async function findNewestLocalSourceMtime(paths: string[]) {
|