feat: deploy Pascal from vendored source
This commit is contained in:
parent
40ff3ca851
commit
5260502507
2
.gitignore
vendored
2
.gitignore
vendored
@ -87,7 +87,7 @@ checkpoints/
|
||||
# 第三方参考源码(不提交到git)
|
||||
reference-sources/
|
||||
|
||||
# Local self-hosted Pascal Editor checkout.
|
||||
# Legacy external Pascal Editor checkout (the managed source is under services/).
|
||||
.pascal-editor/
|
||||
|
||||
# Drizzle migrations must be versioned (override the global *.sql ignore above)
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
/* include utility classes in streamdown */
|
||||
@source '../node_modules/streamdown/dist/index.js';
|
||||
@source not '../services/pascal-editor';
|
||||
|
||||
/* custom variant for setting dark mode programmatically */
|
||||
@custom-variant dark (&:is(.dark, .dark *));
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
"!lib/db/migrations/meta",
|
||||
"!public/vendor",
|
||||
"!public/three",
|
||||
"!services/pascal-editor",
|
||||
"!vercel.json"
|
||||
]
|
||||
},
|
||||
|
||||
@ -2,10 +2,11 @@
|
||||
|
||||
## Current Shape
|
||||
|
||||
The app now exposes a first-phase Pascal Editor workspace at `/pascal-editor`.
|
||||
It is intentionally iframe-based so Pascal can be self-hosted as a standalone
|
||||
Next app without forcing its unpublished `@pascal-app/nodes` workspace package
|
||||
into the main application dependency graph.
|
||||
The app exposes a Pascal Editor workspace at `/pascal-editor`. Its customized
|
||||
source is versioned with the main repository under `services/pascal-editor`,
|
||||
while it remains an independently built Next app embedded through an iframe.
|
||||
This keeps Pascal's Bun workspace and `@pascal-app/nodes` dependency graph out
|
||||
of the host application's pnpm dependency graph.
|
||||
|
||||
The wrapper route is protected by the host application's existing login system.
|
||||
Unauthenticated users are redirected to `/login?callbackUrl=/pascal-editor`.
|
||||
@ -26,11 +27,10 @@ loading a broken iframe.
|
||||
## Why Iframe First
|
||||
|
||||
`@pascal-app/core`, `@pascal-app/viewer`, and `@pascal-app/editor` are published
|
||||
on npm, but the official standalone app still depends on `@pascal-app/nodes`
|
||||
from its monorepo workspace. That package registers the built-in node
|
||||
definitions used by walls, doors, windows, levels, roofs, stairs, and other
|
||||
editable building elements. Until it is published or vendored, a pure npm-based
|
||||
native React integration would be incomplete.
|
||||
on npm, but the standalone app also depends on its monorepo workspace packages.
|
||||
Keeping the complete Pascal source tree below `services/pascal-editor` preserves
|
||||
the built-in walls, doors, windows, levels, roofs, stairs, MCP tools, and our AI
|
||||
Agent customization without coupling the host build to those packages.
|
||||
|
||||
## Deployment Options
|
||||
|
||||
@ -42,9 +42,9 @@ Run Pascal Editor as a local standalone service:
|
||||
pnpm pascal:dev
|
||||
```
|
||||
|
||||
The helper clones `pascalorg/editor` into the ignored `.pascal-editor/`
|
||||
directory on first run, installs its dependencies, and starts `apps/editor` on
|
||||
`http://localhost:3002`.
|
||||
The helper uses `services/pascal-editor`, installs its dependencies when needed,
|
||||
and starts `apps/editor` on `http://localhost:3002`. Set `PASCAL_EDITOR_DIR` only
|
||||
when deliberately testing a different Pascal checkout.
|
||||
|
||||
Then open:
|
||||
|
||||
@ -121,13 +121,20 @@ For repeatable deployment and upgrades on additional servers, use
|
||||
variables, health check, real-model smoke test, and rollback behavior are
|
||||
documented in `docs/pascal-production-deployment.md`.
|
||||
|
||||
## Next Step
|
||||
## Source Maintenance
|
||||
|
||||
After the iframe POC is stable, the native integration path is:
|
||||
`services/pascal-editor` was imported with Git subtree so its upstream history
|
||||
can still be refreshed deliberately. Apply and test upstream updates in a
|
||||
dedicated branch before merging them with our localization, host authentication,
|
||||
scene storage, and AI Agent changes:
|
||||
|
||||
1. Pin a Pascal upstream commit.
|
||||
2. Vendor or workspace-link `packages/nodes` as `@pascal-app/nodes`.
|
||||
3. Add Pascal packages to `transpilePackages`.
|
||||
4. Upgrade `three` to the Pascal-compatible `^0.184` line and retest existing
|
||||
3D/CAD surfaces.
|
||||
5. Wire `Editor` `onLoad` / `onSave` to our project storage APIs.
|
||||
```bash
|
||||
git subtree pull \
|
||||
--prefix=services/pascal-editor \
|
||||
https://github.com/pascalorg/editor.git main \
|
||||
--squash
|
||||
```
|
||||
|
||||
Production servers do not run this command. They only pull the reviewed main
|
||||
repository and let `pnpm pascal:deploy` sync the vendored source into the
|
||||
isolated runtime directory.
|
||||
|
||||
@ -1,32 +1,30 @@
|
||||
# Pascal Editor 可复用生产部署
|
||||
|
||||
本项目把 Pascal Editor 作为独立 Bun/Next.js 服务运行,并通过主站 Nginx
|
||||
同域挂载。部署脚本会复用主站登录态、系统设置中显式标记的“多模态模型”和主站
|
||||
Git 仓库里的 `pascal-editor-ai-agent` 独立分支。
|
||||
Pascal Editor 的定制源码位于主仓库 `services/pascal-editor`,以独立
|
||||
Bun/Next.js 服务运行,并通过主站 Nginx 同域挂载。新服务器只需拉取
|
||||
主仓库,无需再克隆或维护 Pascal 独立分支。
|
||||
|
||||
## 默认结构
|
||||
|
||||
| 项目 | 默认值 |
|
||||
| --- | --- |
|
||||
| 主站目录 | 当前仓库目录 |
|
||||
| 主站源码 | 当前仓库目录 |
|
||||
| Pascal 内置源码 | `services/pascal-editor` |
|
||||
| Pascal 运行副本 | `/opt/pascal-editor` |
|
||||
| Pascal 用户数据 | `/var/lib/pascal-editor` |
|
||||
| 主站 PM2 服务 | `ai-chatbot` |
|
||||
| 主站内部地址 | `http://127.0.0.1:3125` |
|
||||
| Pascal 源码 | `/opt/pascal-editor` |
|
||||
| Pascal 数据 | `/var/lib/pascal-editor` |
|
||||
| Pascal PM2 服务 | `pascal-editor` |
|
||||
| Pascal 监听 | `127.0.0.1:3002` |
|
||||
| 同域路径 | `/pascal-service` |
|
||||
| Pascal Git 分支 | `pascal-editor-ai-agent` |
|
||||
|
||||
Pascal 端口不对公网开放。Nginx 会先通过主站
|
||||
`/api/internal/pascal/access` 校验登录 Cookie,再把可信用户 ID 注入 Pascal。
|
||||
场景的创建、列表、读取、保存、删除、事件流和 AI Agent 都检查同一个
|
||||
`ownerId`。
|
||||
`/opt/pascal-editor` 是部署脚本生成的运行副本,不是第二个源码仓库,
|
||||
不应在该目录直接修改代码。Pascal 端口不对公网开放。Nginx 先通过
|
||||
`/api/internal/pascal/access` 校验主站登录 Cookie,再注入可信用户 ID。
|
||||
场景数据按 `ownerId` 隔离。
|
||||
|
||||
## 首次部署
|
||||
|
||||
在目标服务器先部署好主站并确认主站 Git remote 能读取
|
||||
`pascal-editor-ai-agent` 分支,然后执行:
|
||||
目标服务器部署好主站后执行:
|
||||
|
||||
```bash
|
||||
cd /var/www/ai-chatbot
|
||||
@ -41,39 +39,43 @@ sudo env \
|
||||
脚本会按顺序:
|
||||
|
||||
1. 生成或复用 `PASCAL_PROXY_SECRET`,写入主站 `.env.local`。
|
||||
2. 构建并重启主站。
|
||||
3. 安装固定版本 Bun(默认 `1.3.0`)。
|
||||
4. 克隆或快进 Pascal 独立分支。
|
||||
2. 安装主站开发依赖,构建并重启主站。
|
||||
3. 安装固定版本 Bun(默认 `1.3.0`)和 `rsync`。
|
||||
4. 将 `services/pascal-editor` 同步为独立运行副本。
|
||||
5. 写入仅 root 可读的 Pascal 生产环境文件。
|
||||
6. 安装依赖、构建 Pascal,并注册 PM2 服务。
|
||||
7. 渲染 Nginx 片段、执行 `nginx -t`,成功后热重载。
|
||||
7. 渲染 Nginx 片段,校验成功后热重载。
|
||||
8. 检查主站、Pascal、Agent 状态和主站模型网关。
|
||||
|
||||
主站环境文件和 Nginx 配置会备份到 `/var/backups/pascal-deploy`。Nginx
|
||||
校验失败时,脚本会立即恢复执行前的配置。
|
||||
主站环境文件、Nginx 配置以及旧 Pascal Git 元数据会备份到
|
||||
`/var/backups/pascal-deploy`。Nginx 校验失败时会恢复原配置。
|
||||
|
||||
## 日常更新
|
||||
|
||||
主站和 Pascal 分支有新提交后,重复执行同一个命令即可。脚本只允许 Git
|
||||
快进更新;如果 `/opt/pascal-editor` 有本地修改,会停止部署,不会覆盖现场
|
||||
文件。
|
||||
以后只需更新主仓库,并重复执行部署命令:
|
||||
|
||||
```bash
|
||||
git pull --ff-only origin main
|
||||
sudo env PASCAL_PUBLIC_ORIGIN=https://example.com pnpm pascal:deploy
|
||||
```
|
||||
|
||||
`rsync --delete` 会更新运行副本,但保留 `/opt/pascal-editor/.env.production`。
|
||||
用户数据始终位于独立的 `PASCAL_DATA_DIR`,不会被代码同步覆盖。
|
||||
|
||||
只做无模型费用的健康检查:
|
||||
|
||||
```bash
|
||||
sudo env \
|
||||
PASCAL_PUBLIC_ORIGIN=https://example.com \
|
||||
pnpm pascal:check
|
||||
sudo env PASCAL_PUBLIC_ORIGIN=https://example.com pnpm pascal:check
|
||||
```
|
||||
|
||||
执行一次真实自然语言建模、验证节点已落库并自动删除临时场景:
|
||||
执行一次真实自然语言建模,验证节点落库后删除临时场景:
|
||||
|
||||
```bash
|
||||
sudo env PASCAL_SMOKE_CONFIRM=1 pnpm pascal:smoke
|
||||
```
|
||||
|
||||
真实冒烟会调用当前系统设置中显式标记的“多模态模型”,因此默认不会在一键部署时
|
||||
执行。需要每次部署自动执行时设置 `RUN_AGENT_SMOKE_TEST=true`。
|
||||
真实冒烟会调用系统设置中显式标记的“多模态模型”,默认不在一键部署
|
||||
时执行。需要每次部署自动执行时设置 `RUN_AGENT_SMOKE_TEST=true`。
|
||||
|
||||
## 常用覆盖项
|
||||
|
||||
@ -83,16 +85,15 @@ sudo env PASCAL_SMOKE_CONFIRM=1 pnpm pascal:smoke
|
||||
| `MAIN_ENV_FILE` | 主站环境文件 |
|
||||
| `MAIN_PM2_NAME` | 主站 PM2 服务名 |
|
||||
| `MAIN_INTERNAL_URL` | Pascal 调用主站网关的地址 |
|
||||
| `MAIN_NGINX_UPSTREAM` | Nginx 主站 upstream,例如 `127.0.0.1:3125` |
|
||||
| `MAIN_NGINX_UPSTREAM` | Nginx 主站 upstream |
|
||||
| `BUILD_MAIN_APP=false` | 跳过主站安装、构建和重启 |
|
||||
| `PASCAL_INSTALL_DIR` | Pascal 源码目录 |
|
||||
| `PASCAL_DATA_DIR` | SQLite 数据目录 |
|
||||
| `PASCAL_GIT_REPO` | Pascal 分支所在 Git 仓库;默认使用主站 origin |
|
||||
| `PASCAL_GIT_REF` | Pascal 分支或标签 |
|
||||
| `PASCAL_SOURCE_DIR` | Pascal 内置源码目录 |
|
||||
| `PASCAL_INSTALL_DIR` | Pascal 运行副本目录 |
|
||||
| `PASCAL_DATA_DIR` | SQLite 用户数据目录 |
|
||||
| `PASCAL_PORT` | Pascal 本地监听端口 |
|
||||
| `PASCAL_BASE_PATH` | 同域挂载路径 |
|
||||
| `PASCAL_PUBLIC_ORIGIN` | 公网主站 Origin,不带末尾斜杠 |
|
||||
| `NGINX_SITE_CONFIG` | 需要加入 Pascal include 的 HTTPS server 配置 |
|
||||
| `NGINX_SITE_CONFIG` | 需加入 Pascal include 的 HTTPS server 配置 |
|
||||
| `INSTALL_NGINX=false` | 仅部署服务,不修改 Nginx |
|
||||
| `PASCAL_BUN_VERSION` | 固定 Bun 版本 |
|
||||
| `PASCAL_BACKUP_DIR` | 环境与 Nginx 配置备份目录 |
|
||||
@ -103,9 +104,10 @@ sudo env PASCAL_SMOKE_CONFIRM=1 pnpm pascal:smoke
|
||||
pm2 status
|
||||
pm2 logs pascal-editor --lines 100
|
||||
curl http://127.0.0.1:3002/pascal-service/api/health
|
||||
cat /opt/pascal-editor/.pascal-source-version
|
||||
nginx -t
|
||||
```
|
||||
|
||||
升级时不要把主站源码复制到 Pascal 目录,也不要把本地测试数据库上传到
|
||||
服务器。主站始终更新 `main`,Pascal 始终更新独立分支,用户场景只保存在
|
||||
不要将本地测试数据库放进 `services/pascal-editor`,也不要直接修改
|
||||
`/opt/pascal-editor`。代码只更新主仓 `main`,用户场景只保存在
|
||||
`PASCAL_DATA_DIR`。
|
||||
|
||||
@ -12,9 +12,8 @@ MAIN_NGINX_UPSTREAM="${MAIN_NGINX_UPSTREAM:-127.0.0.1:3125}"
|
||||
BUILD_MAIN_APP="${BUILD_MAIN_APP:-true}"
|
||||
|
||||
PASCAL_INSTALL_DIR="${PASCAL_INSTALL_DIR:-/opt/pascal-editor}"
|
||||
PASCAL_SOURCE_DIR="${PASCAL_SOURCE_DIR:-$MAIN_APP_DIR/services/pascal-editor}"
|
||||
PASCAL_DATA_DIR="${PASCAL_DATA_DIR:-/var/lib/pascal-editor}"
|
||||
PASCAL_GIT_REF="${PASCAL_GIT_REF:-pascal-editor-ai-agent}"
|
||||
PASCAL_GIT_REPO="${PASCAL_GIT_REPO:-}"
|
||||
PASCAL_PM2_NAME="${PASCAL_PM2_NAME:-pascal-editor}"
|
||||
PASCAL_PORT="${PASCAL_PORT:-3002}"
|
||||
PASCAL_NGINX_UPSTREAM="${PASCAL_NGINX_UPSTREAM:-127.0.0.1:${PASCAL_PORT}}"
|
||||
@ -127,6 +126,17 @@ install_bun() {
|
||||
[ -x "$PASCAL_BUN_BIN" ] || die "Bun installation did not create $PASCAL_BUN_BIN"
|
||||
}
|
||||
|
||||
install_rsync() {
|
||||
if command -v rsync >/dev/null 2>&1; then
|
||||
return
|
||||
fi
|
||||
|
||||
[ "$(id -u)" -eq 0 ] || die "Installing rsync requires root; install rsync manually"
|
||||
require_command apt-get
|
||||
apt-get update -qq
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq rsync
|
||||
}
|
||||
|
||||
configure_main_app() {
|
||||
local secret="$1"
|
||||
local next_env_backup=""
|
||||
@ -176,29 +186,40 @@ configure_main_app() {
|
||||
)
|
||||
}
|
||||
|
||||
resolve_pascal_repo() {
|
||||
if [ -n "$PASCAL_GIT_REPO" ]; then
|
||||
printf '%s' "$PASCAL_GIT_REPO"
|
||||
return
|
||||
fi
|
||||
git -C "$MAIN_APP_DIR" remote get-url origin
|
||||
}
|
||||
sync_pascal_source() {
|
||||
[ -f "$PASCAL_SOURCE_DIR/package.json" ] ||
|
||||
die "Vendored Pascal source not found: $PASCAL_SOURCE_DIR"
|
||||
[ -f "$PASCAL_SOURCE_DIR/apps/editor/package.json" ] ||
|
||||
die "Pascal editor package not found below $PASCAL_SOURCE_DIR"
|
||||
[ "$PASCAL_INSTALL_DIR" != "/" ] || die "PASCAL_INSTALL_DIR cannot be /"
|
||||
[ "$PASCAL_INSTALL_DIR" != "$MAIN_APP_DIR" ] ||
|
||||
die "PASCAL_INSTALL_DIR cannot overwrite MAIN_APP_DIR"
|
||||
[ "$PASCAL_INSTALL_DIR" != "$PASCAL_SOURCE_DIR" ] ||
|
||||
die "PASCAL_INSTALL_DIR must be separate from PASCAL_SOURCE_DIR"
|
||||
|
||||
install_rsync
|
||||
mkdir -p "$PASCAL_INSTALL_DIR" "$PASCAL_BACKUP_DIR"
|
||||
|
||||
checkout_pascal() {
|
||||
local repo="$1"
|
||||
if [ -d "$PASCAL_INSTALL_DIR/.git" ]; then
|
||||
[ -z "$(git -C "$PASCAL_INSTALL_DIR" status --porcelain)" ] ||
|
||||
die "$PASCAL_INSTALL_DIR has local Git changes; refusing to overwrite them"
|
||||
git -C "$PASCAL_INSTALL_DIR" fetch origin "$PASCAL_GIT_REF"
|
||||
git -C "$PASCAL_INSTALL_DIR" checkout "$PASCAL_GIT_REF"
|
||||
git -C "$PASCAL_INSTALL_DIR" pull --ff-only origin "$PASCAL_GIT_REF"
|
||||
return
|
||||
die "$PASCAL_INSTALL_DIR has legacy local Git changes; refusing to overwrite them"
|
||||
local legacy_git_backup="$PASCAL_BACKUP_DIR/legacy-pascal-git-$(date +%Y%m%d%H%M%S)"
|
||||
log "Archiving legacy Pascal Git metadata to $legacy_git_backup"
|
||||
mv "$PASCAL_INSTALL_DIR/.git" "$legacy_git_backup"
|
||||
fi
|
||||
|
||||
[ ! -e "$PASCAL_INSTALL_DIR" ] ||
|
||||
die "$PASCAL_INSTALL_DIR exists but is not a Git checkout"
|
||||
mkdir -p "$(dirname "$PASCAL_INSTALL_DIR")"
|
||||
git clone --single-branch --branch "$PASCAL_GIT_REF" "$repo" "$PASCAL_INSTALL_DIR"
|
||||
log "Syncing vendored Pascal source from $PASCAL_SOURCE_DIR"
|
||||
rsync -a --delete \
|
||||
--exclude '.env.production' \
|
||||
--exclude '.git/' \
|
||||
--exclude '.next/' \
|
||||
--exclude '.turbo/' \
|
||||
--exclude 'node_modules/' \
|
||||
"$PASCAL_SOURCE_DIR/" "$PASCAL_INSTALL_DIR/"
|
||||
|
||||
if git -C "$MAIN_APP_DIR" rev-parse --verify HEAD >/dev/null 2>&1; then
|
||||
git -C "$MAIN_APP_DIR" rev-parse HEAD >"$PASCAL_INSTALL_DIR/.pascal-source-version"
|
||||
fi
|
||||
}
|
||||
|
||||
write_pascal_env() {
|
||||
@ -226,7 +247,7 @@ build_pascal() {
|
||||
mkdir -p "$PASCAL_DATA_DIR"
|
||||
chmod 700 "$PASCAL_DATA_DIR"
|
||||
export PATH="$(dirname "$PASCAL_BUN_BIN"):$PATH"
|
||||
log "Installing and building Pascal from $PASCAL_GIT_REF"
|
||||
log "Installing and building vendored Pascal service"
|
||||
(
|
||||
cd "$PASCAL_INSTALL_DIR"
|
||||
"$PASCAL_BUN_BIN" install --frozen-lockfile
|
||||
@ -369,7 +390,7 @@ main() {
|
||||
[ "$(id -u)" -eq 0 ] || die "Production deployment must run as root"
|
||||
configure_main_app "$secret"
|
||||
install_bun
|
||||
checkout_pascal "$(resolve_pascal_repo)"
|
||||
sync_pascal_source
|
||||
write_pascal_env "$secret"
|
||||
build_pascal
|
||||
start_pascal
|
||||
|
||||
@ -1,22 +1,13 @@
|
||||
#!/usr/bin/env node
|
||||
import { spawn, spawnSync } from "node:child_process";
|
||||
import {
|
||||
copyFileSync,
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
readFileSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
import { existsSync, writeFileSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
const cwd = process.cwd();
|
||||
const pascalDir = path.resolve(
|
||||
cwd,
|
||||
process.env.PASCAL_EDITOR_DIR || ".pascal-editor"
|
||||
process.env.PASCAL_EDITOR_DIR || "services/pascal-editor"
|
||||
);
|
||||
const repoUrl =
|
||||
process.env.PASCAL_EDITOR_REPO || "https://github.com/pascalorg/editor.git";
|
||||
const repoRef = process.env.PASCAL_EDITOR_REF || "main";
|
||||
const port = process.env.PASCAL_EDITOR_PORT || "3002";
|
||||
|
||||
function run(command, args, options = {}) {
|
||||
@ -36,72 +27,6 @@ function commandExists(command) {
|
||||
return result.status === 0;
|
||||
}
|
||||
|
||||
function patchNestedNextRoot() {
|
||||
const configPath = path.join(pascalDir, "apps/editor/next.config.ts");
|
||||
if (!existsSync(configPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let config = readFileSync(configPath, "utf8");
|
||||
if (!config.includes("import path from 'node:path'")) {
|
||||
config = config.replace(
|
||||
"import type { NextConfig } from 'next'\n",
|
||||
"import path from 'node:path'\nimport type { NextConfig } from 'next'\n"
|
||||
);
|
||||
}
|
||||
|
||||
if (!config.includes("root: path.resolve(process.cwd(), '../..')")) {
|
||||
config = config.replace(
|
||||
" turbopack: {\n",
|
||||
" turbopack: {\n root: path.resolve(process.cwd(), '../..'),\n"
|
||||
);
|
||||
}
|
||||
|
||||
writeFileSync(configPath, config, "utf8");
|
||||
}
|
||||
|
||||
function ensureSparseCheckout() {
|
||||
run(
|
||||
"git",
|
||||
[
|
||||
"-C",
|
||||
pascalDir,
|
||||
"sparse-checkout",
|
||||
"set",
|
||||
"apps/editor",
|
||||
"packages",
|
||||
"tooling",
|
||||
"styles",
|
||||
],
|
||||
{ cwd }
|
||||
);
|
||||
}
|
||||
|
||||
function patchCssImports() {
|
||||
const source = path.join(pascalDir, "styles/elevation.css");
|
||||
const targetDir = path.join(pascalDir, "apps/editor/styles");
|
||||
const target = path.join(targetDir, "elevation.css");
|
||||
const globalsPath = path.join(pascalDir, "apps/editor/app/globals.css");
|
||||
|
||||
if (existsSync(source)) {
|
||||
mkdirSync(targetDir, { recursive: true });
|
||||
copyFileSync(source, target);
|
||||
}
|
||||
|
||||
if (!existsSync(globalsPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const globals = readFileSync(globalsPath, "utf8");
|
||||
const patched = globals.replace(
|
||||
'../../../styles/elevation.css',
|
||||
'../styles/elevation.css'
|
||||
);
|
||||
if (patched !== globals) {
|
||||
writeFileSync(globalsPath, patched, "utf8");
|
||||
}
|
||||
}
|
||||
|
||||
function runPackageScript(packageManager, packageDir, scriptName) {
|
||||
if (packageManager === "bun") {
|
||||
run("bun", ["--cwd", packageDir, "run", scriptName], { cwd: pascalDir });
|
||||
@ -127,36 +52,18 @@ function ensureBuiltWorkspacePackages(packageManager) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!existsSync(pascalDir)) {
|
||||
mkdirSync(path.dirname(pascalDir), { recursive: true });
|
||||
run("git", [
|
||||
"clone",
|
||||
"--depth",
|
||||
"1",
|
||||
"--filter=blob:none",
|
||||
"--sparse",
|
||||
"--branch",
|
||||
repoRef,
|
||||
repoUrl,
|
||||
pascalDir,
|
||||
]);
|
||||
} else if (!existsSync(path.join(pascalDir, ".git"))) {
|
||||
if (!existsSync(path.join(pascalDir, "apps/editor/package.json"))) {
|
||||
console.error(
|
||||
`${pascalDir} already exists but is not a git checkout. Move it away or set PASCAL_EDITOR_DIR.`
|
||||
`Vendored Pascal Editor source was not found at ${pascalDir}. Set PASCAL_EDITOR_DIR to override it.`
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
ensureSparseCheckout();
|
||||
patchCssImports();
|
||||
|
||||
const envLocalPath = path.join(pascalDir, ".env.local");
|
||||
if (!existsSync(envLocalPath)) {
|
||||
writeFileSync(envLocalPath, `PORT=${port}\n`, "utf8");
|
||||
}
|
||||
|
||||
patchNestedNextRoot();
|
||||
|
||||
const hasBun = commandExists("bun");
|
||||
const hasNpm = commandExists("npm");
|
||||
const hasNodeModules = existsSync(path.join(pascalDir, "node_modules"));
|
||||
|
||||
19
services/pascal-editor/HOST_INTEGRATION.md
Normal file
19
services/pascal-editor/HOST_INTEGRATION.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Host Application Integration
|
||||
|
||||
This directory is the source of truth for the Pascal Editor service shipped
|
||||
with the host application. It originated from `pascalorg/editor` and includes
|
||||
the host authentication, user-scoped scene storage, Chinese localization, and
|
||||
AI Agent integration maintained by this project.
|
||||
|
||||
## Boundaries
|
||||
|
||||
- The host application uses pnpm and does not install this workspace as part of
|
||||
its own dependency graph.
|
||||
- Pascal uses its own Bun lockfile and is built as an independent Next service.
|
||||
- Production deploys copy this directory to `/opt/pascal-editor`.
|
||||
- Runtime secrets remain in `/opt/pascal-editor/.env.production`.
|
||||
- User scene data remains outside both source trees in `/var/lib/pascal-editor`.
|
||||
|
||||
Run `pnpm pascal:dev` from the host repository for local development. Run
|
||||
`pnpm pascal:deploy` as root on a production server after pulling the host main
|
||||
branch. Never commit runtime environment files or SQLite scene databases here.
|
||||
@ -31,5 +31,5 @@
|
||||
"next.config.js",
|
||||
".next/dev/types/**/*.ts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
"exclude": ["node_modules", "services/pascal-editor"]
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user