Files
Genarrative/.hermes/skills/genarrative-dev-stack-port-routing/SKILL.md
历冰郁-hermes版 f74717c415
Some checks failed
CI / verify (push) Has been cancelled
fix(dev): resolve local stack ports before startup
2026-05-10 20:00:42 +08:00

7.6 KiB
Raw Blame History

name, short_description, description, version, author, license, metadata
name short_description description version author license metadata
genarrative-dev-stack-port-routing 修改 Genarrative 本地 dev 启动端口、代理目标、端口冲突处理时使用。 在 Genarrative 中修改 npm run dev / npm run dev:rust / npm run dev:web 的本地启动端口、端口可用性探测、端口漂移、SpacetimeDB publish server、api-server 环境变量、Vite 代理目标和后台 admin-web 启动串联时使用。 1.0.0 Hermes Agent MIT
hermes
tags related_skills
Genarrative
dev-stack
端口探测
Vite
api-server
SpacetimeDB
npm-run-dev
genarrative-admin-backoffice

Genarrative 本地 dev 启动端口与代理目标串联流程

用于维护 Genarrative 本地开发栈启动脚本,重点覆盖 npm run dev / npm run dev:rust / npm run dev:web 的端口检查、端口漂移和后续流程目标传递。

适用场景

  • 修改 scripts/dev-rust-stack.shscripts/dev-web-rust.mjsscripts/dev-stack-port-utils.mjs
  • 处理 3000310131028082 等端口被占用导致本地开发栈启动失败。
  • 排查 Vite 代理仍指向旧 api-server 端口、前端打开了旧 dev server、后台代理错配。
  • 调整 SpacetimeDB standalone、publish、Rust api-server、主站 Vite、后台 Vite 的启动顺序。
  • 修改本地联调文档或 .hermes/shared-memory/pitfalls.md 中的 dev 启动口径。

当前端口职责

默认优先端口:

  1. 主站 Vite3000,对浏览器通常展示为 http://127.0.0.1:<web-port>/
  2. Rust api-server8082,健康检查为 http://127.0.0.1:<api-port>/healthz
  3. SpacetimeDB standalone3101,健康检查为 http://127.0.0.1:<spacetime-port>/v1/ping
  4. 后台 Vite3102,后台地址为 http://127.0.0.1:<admin-web-port>/admin/

端口不可用时,脚本会从优先端口开始向后寻找可用端口。后续流程必须以解析后的实际端口为准,不能继续使用默认端口。

实现入口

  • package.json
    • devdev:rust:执行 node scripts/run-bash-script.mjs scripts/dev-rust-stack.sh
    • dev:web:执行 node scripts/dev-web-rust.mjs
  • scripts/dev-stack-port-utils.mjs
    • isPortAvailable(...):探测端口是否可监听。
    • findAvailablePort(...):从优先端口向后寻找可用端口,0 表示申请临时端口。
    • resolveDevStackPorts(...):一次性解析 SpacetimeDB、api-server、主站 Vite、后台 Vite 端口,并避免本次解析结果互相冲突。
    • CLI 模式:node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:3101 api:127.0.0.1:8082 web:0.0.0.0:3000 adminWeb:127.0.0.1:3102
  • scripts/dev-rust-stack.sh
    • 解析 CLI 参数后,先计算 API_TARGET_HOSTADMIN_WEB_TARGET_HOST
    • 调用 resolve_dev_stack_ports 覆盖 SPACETIME_PORTAPI_PORTWEB_PORTADMIN_WEB_PORT
    • 再构造 SPACETIME_SERVERRUST_SERVER_TARGET
  • scripts/dev-web-rust.mjs
    • 单独启动主站前端时,也先用 findAvailablePort 检查 WEB_PORT / 默认 3000

必须保持的传递链路

npm run dev / npm run dev:rust 中端口解析后,必须同步到以下位置:

  1. SpacetimeDB 启动:spacetime start --listen-addr "${SPACETIME_HOST}:${SPACETIME_PORT}"
  2. SpacetimeDB 发布:spacetime publish ... --server "${SPACETIME_SERVER}"
  3. Rust api-serverGENARRATIVE_API_HOSTGENARRATIVE_API_PORTGENARRATIVE_SPACETIME_SERVER_URLGENARRATIVE_SPACETIME_DATABASE
  4. api-server 健康检查:wait_for_api_server "${RUST_SERVER_TARGET}/healthz" ...
  5. 主站 ViteRUST_SERVER_TARGETGENARRATIVE_RUNTIME_SERVER_TARGETADMIN_WEB_TARGETADMIN_WEB_PORT--port=${WEB_PORT}--host=${WEB_HOST}
  6. 后台 ViteADMIN_API_TARGETGENARRATIVE_API_TARGETGENARRATIVE_API_PORT--port=${ADMIN_WEB_PORT}
  7. 控制台日志:[dev:ports][dev:rust] web/admin web/rust api/spacetime 必须显示最终实际地址。

如果只改了其中一段,通常会出现:浏览器打开的前端可用,但 /api/* 代理到旧端口;后台页面可用但后台 API 失败SpacetimeDB 启动在新端口但 publish 仍发往旧端口。

修改流程

  1. 先读当前脚本和文档:
    • scripts/dev-stack-port-utils.mjs
    • scripts/dev-rust-stack.sh
    • scripts/dev-web-rust.mjs
    • docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md
    • .hermes/shared-memory/pitfalls.md
  2. 优先改公共端口工具,不要把端口探测逻辑复制到多个脚本。
  3. 对 Bash 脚本只做局部补丁,避免整文件重写导致中文注释或换行大面积变化。
  4. 修改 dev-rust-stack.sh 时确认变量顺序:
    • 先有 REPO_ROOT
    • 再计算 API_TARGET_HOST / ADMIN_WEB_TARGET_HOST
    • 再调用端口解析工具。
    • 再构造 SPACETIME_SERVER / RUST_SERVER_TARGET
  5. 修改 dev:web 时不要自动改后端目标策略;dev:web 只负责主站 Vite 端口可用性与已有后端目标选择。
  6. 同步更新技术文档和团队共享记忆。

测试与验证

最小验证:

bash -n scripts/dev-rust-stack.sh
npm run test -- scripts/dev-stack-port-utils.test.ts
npm run check:encoding
node scripts/dev-stack-port-utils.mjs resolve-dev-stack spacetime:127.0.0.1:0 api:127.0.0.1:0 web:0.0.0.0:0 adminWeb:127.0.0.1:0

端口冲突回归测试建议:

  1. 用测试或临时 Node server 占用某个优先端口。
  2. 调用 findAvailablePort,断言结果大于被占用端口。
  3. 调用 resolveDevStackPorts,断言四个结果互不相同。
  4. 如果实际启动完整栈,观察控制台:
    • [dev:ports] ... 不可用,改用 ...
    • [dev:rust] rust api: http://...:<actual-api-port>
    • [dev:rust] spacetime: http://...:<actual-spacetime-port>
    • 主站和后台 Vite 启动端口与日志一致。

完整启动属于长驻进程。需要 smoke 时用 background 方式启动,并另开命令检查 /healthz/v1/ping 和页面端口;不要等待 npm run dev 自然退出。

常见坑

  1. 只让 Vite 自己漂移端口。 这样终端可能出现可访问前端,但脚本和文档仍认为是 3000,后台目标或日志会错。
  2. 只改 SpacetimeDB start不改 publish。 standalone 可能监听新端口,但 publish 仍连旧 3101
  3. 只改 GENARRATIVE_API_PORT,不改 RUST_SERVER_TARGET api-server 已在新端口监听,但 Vite 代理仍打旧端口。
  4. 使用 0.0.0.0 作为浏览器访问地址。 监听可以是 0.0.0.0,展示给用户和健康检查通常用 127.0.0.1
  5. 端口探测和实际启动之间存在竞态。 已经探测可用的端口仍可能被外部进程抢占SpacetimeDB 启动后仍要解析实际监听地址api-server 和 Vite 失败时要打印清晰日志。
  6. 运行全仓库 lint 误判。 当前仓库可能有既有 lint 问题。验证本功能时优先运行定向测试、Bash 语法检查、编码检查,并在最终说明中区分既有 lint 失败与本次改动。

验收清单

  • 端口工具有测试覆盖端口被占用和多端口互斥解析。
  • dev-rust-stack.sh 通过 bash -n
  • npm run dev / npm run dev:rust 的 SpacetimeDB、publish、api-server、主站 Vite、后台 Vite 都使用实际端口。
  • npm run dev:web 在主站端口不可用时能切换到可用端口。
  • 文档同步更新 docs/technical/RUST_LOCAL_AND_REMOTE_DEPLOYMENT_SCRIPTS_2026-04-22.md
  • 长期踩坑同步更新 .hermes/shared-memory/pitfalls.md
  • 修改中文文件后运行 npm run check:encoding