chore: checkpoint local workspace changes

This commit is contained in:
2026-04-23 12:45:15 +08:00
parent 3eb9390e8f
commit a6cd9afcbb
47 changed files with 2154 additions and 529 deletions

View File

@@ -484,6 +484,10 @@ API_LOG="${GENARRATIVE_API_LOG:-info,tower_http=info}"
WEB_HOST="${GENARRATIVE_WEB_HOST:-__GENARRATIVE_DEFAULT_WEB_HOST__}"
WEB_PORT="${GENARRATIVE_WEB_PORT:-__GENARRATIVE_DEFAULT_WEB_PORT__}"
# 日志默认落文件,显式关闭 ANSI 颜色码,避免控制字符写入 *.log。
export NO_COLOR="${NO_COLOR:-1}"
export CARGO_TERM_COLOR="${CARGO_TERM_COLOR:-never}"
require_command() {
local command_name="$1"
@@ -651,6 +655,7 @@ cat >"${TARGET_DIR}/README.md" <<EOF
- 启动时会先加载发布目录根部的 \`.env\` 与 \`.env.local\`,再回退到脚本内默认值。
- 脚本内默认值来自构建时的 `--database`、`--api-port`、`--web-port`、`--spacetime-host`、`--spacetime-port` 参数。
- 默认导出 \`NO_COLOR=1\` 与 \`CARGO_TERM_COLOR=never\`,避免 ANSI 颜色控制码写入日志文件;如确有需要可在启动前显式覆盖。
- \`GENARRATIVE_WEB_HOST\` / \`GENARRATIVE_WEB_PORT\`
- \`GENARRATIVE_API_HOST\` / \`GENARRATIVE_API_PORT\` / \`GENARRATIVE_API_LOG\`
- \`GENARRATIVE_SPACETIME_HOST\` / \`GENARRATIVE_SPACETIME_PORT\`

View File

@@ -1,4 +1,4 @@
import {spawn} from 'node:child_process';
import {spawn, spawnSync} from 'node:child_process';
import {existsSync, readFileSync} from 'node:fs';
import net from 'node:net';
import path from 'node:path';
@@ -33,6 +33,14 @@ const DEFAULT_RUST_API_PORT = '3100';
const DEFAULT_SPACETIME_SERVER_URL = 'http://127.0.0.1:3001';
const DEFAULT_SPACETIME_DATABASE = 'genarrative-dev';
const DEFAULT_INTERNAL_API_SECRET = 'genarrative-dev-internal-bridge';
const spacetimeModulePath = path.join(serverRsRoot, 'crates', 'spacetime-module');
const spacetimeRustBindingsOutDir = path.join(
serverRsRoot,
'crates',
'spacetime-client',
'src',
'module_bindings',
);
function parseEnvContents(contents) {
return contents
@@ -195,6 +203,98 @@ function prependEnvPath(envMap, nextEntry) {
envMap[pathKey] = [nextEntry, ...segments].join(path.delimiter);
}
function resolveSpacetimeCommand() {
const command = process.platform === 'win32' ? 'where' : 'which';
const result = spawnSync(command, ['spacetime'], {
cwd: repoRoot,
env: mergedEnv,
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
});
if (result.status !== 0) {
return null;
}
const firstLine = `${result.stdout || ''}`
.split(/\r?\n/u)
.map((line) => line.trim())
.find(Boolean);
return firstLine || 'spacetime';
}
function runRequiredCommand(command, args, label) {
const result = spawnSync(command, args, {
cwd: repoRoot,
env: mergedEnv,
stdio: 'inherit',
});
if (result.status !== 0) {
console.error(`[dev:node] ${label} failed with exit code ${result.status ?? 1}`);
process.exit(result.status ?? 1);
}
}
function ensureSpacetimeSchemaReady() {
const spacetimeCommand = resolveSpacetimeCommand();
if (!spacetimeCommand) {
console.error(
'[dev:node] Missing `spacetime` CLI. Install or expose it in PATH before starting local dev.',
);
process.exit(1);
}
const spacetimeServerUrl = `${mergedEnv.GENARRATIVE_SPACETIME_SERVER_URL || ''}`.trim();
const spacetimeDatabase = `${mergedEnv.GENARRATIVE_SPACETIME_DATABASE || ''}`.trim();
if (!spacetimeServerUrl || !spacetimeDatabase) {
console.error(
'[dev:node] Missing GENARRATIVE_SPACETIME_SERVER_URL or GENARRATIVE_SPACETIME_DATABASE, cannot publish local schema.',
);
process.exit(1);
}
console.log(
`[dev:node] Publishing spacetime-module to ${spacetimeDatabase} (${spacetimeServerUrl}) before Rust api-server starts...`,
);
runRequiredCommand(
spacetimeCommand,
[
'publish',
spacetimeDatabase,
'--server',
spacetimeServerUrl,
'--module-path',
spacetimeModulePath,
'--yes',
...(mergedEnv.GENARRATIVE_SPACETIME_DELETE_DATA_ON_CONFLICT === '1'
? ['--delete-data=on-conflict']
: []),
],
'spacetime publish',
);
console.log('[dev:node] Generating Rust Spacetime bindings before Rust api-server starts...');
runRequiredCommand(
spacetimeCommand,
[
'generate',
'--no-config',
'--lang',
'rust',
'--out-dir',
spacetimeRustBindingsOutDir,
'--module-path',
spacetimeModulePath,
'--include-private',
'--yes',
],
'spacetime generate (rust)',
);
}
const exampleEnv = readEnvFile(envExamplePath);
const localEnv = readEnvFile(envLocalPath);
const spacetimeConfig = readJsonFile(spacetimeConfigPath);
@@ -292,6 +392,8 @@ console.log(`[dev:node] DATABASE_URL=${redactDatabaseUrl(mergedEnv.DATABASE_URL)
console.log(`[dev:node] VITE_DEV_HOST=${mergedEnv.VITE_DEV_HOST}`);
console.log(`[dev:node] NODE_RUNTIME=${runtimeNodePath}`);
ensureSpacetimeSchemaReady();
const children = new Set();
let shuttingDown = false;
let pendingExitCode = 0;

View File

@@ -9,8 +9,8 @@ usage() {
说明:
1. 如果部署目录已有旧版本且存在 stop.sh则先执行旧版本 stop.sh。
2. 直接清空部署目录中的全部旧文件
3. 把指定发布目录中的内容移动到部署目录。
2. 仅删除并替换发布产物文件,保留部署目录中的运行数据目录
3. 把指定发布目录中的内容覆盖到部署目录。
4. 最后执行新版本 start.sh。
参数:
@@ -33,6 +33,17 @@ require_argument() {
SOURCE_DIR=""
DEPLOY_DIR=""
HOOK_WITH_SUDO="0"
DEPLOY_ITEMS=(
".env"
".env.local"
"README.md"
"api-server"
"spacetime_module.wasm"
"start.sh"
"stop.sh"
"web"
"web-server.mjs"
)
while [[ $# -gt 0 ]]; do
case "$1" in
@@ -114,10 +125,20 @@ else
fi
echo "[jenkins-deploy] 清空部署目录: ${DEPLOY_DIR}"
find "${DEPLOY_DIR}" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
for item in "${DEPLOY_ITEMS[@]}"; do
if [[ -e "${DEPLOY_DIR}/${item}" ]]; then
echo "[jenkins-deploy] 删除旧产物: ${DEPLOY_DIR}/${item}"
rm -rf "${DEPLOY_DIR:?}/${item}"
fi
done
echo "[jenkins-deploy] 移动发布内容: ${SOURCE_DIR} -> ${DEPLOY_DIR}"
find "${SOURCE_DIR}" -mindepth 1 -maxdepth 1 -exec mv {} "${DEPLOY_DIR}/" \;
for item in "${DEPLOY_ITEMS[@]}"; do
if [[ -e "${SOURCE_DIR}/${item}" ]]; then
echo "[jenkins-deploy] 覆盖产物: ${item}"
mv "${SOURCE_DIR}/${item}" "${DEPLOY_DIR}/"
fi
done
chmod +x "${DEPLOY_DIR}/start.sh"