From b8b46a04c388300ed2254846bbd3cb888a600d95 Mon Sep 17 00:00:00 2001 From: sunlei Date: Thu, 25 Jun 2026 09:41:16 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E9=80=82=E9=85=8DNAS=20Codex=20nvm?= =?UTF-8?q?=E8=BF=90=E8=A1=8C=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 ++--- src/selfTest.ts | 14 ++++++++-- src/tools/napcatAutomation.ts | 49 ++++++++++++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 77427a3..8763d40 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ - 生成接口测试计划:接口改动后输出真实调用命令和统一返回结构断言。 - 生成业务链路测试计划:固化 Admin 登录、博客 CRUD、QQBot 扫码/自动回复、更新登录 SSE、FFLogs 命令、系统日志可视化、Web/Playground 回跳。 - 静态检查 NapCat 设备身份护栏:确认 API 仍保留 QQNT 可见 hostname、实体 OUI 风格 MAC、QQNT `machine-info` 写入、持久化 runtime dir 和 `DB_TIMEZONE` 默认值。 -- 生成 NapCatQQ 上游同步与 runtime 发布自动化入口:MCP/CLI 默认 dry-run,覆盖 upstream audit、sync candidate review、runtime readiness、remote dev handoff 和 NAS Codex bootstrap plan;upstream audit 在显式 `execute=true` 且 `useCodex=true` 时可运行 Codex,NAS Codex bootstrap 在显式 `execute=true` 时只返回目录准备和 CLI 包检查/安装计划,不复制 secrets、不写 systemd、不触发发布。 +- 生成 NapCatQQ 上游同步与 runtime 发布自动化入口:MCP/CLI 默认 dry-run,覆盖 upstream audit、sync candidate review、runtime readiness、remote dev handoff 和 NAS Codex bootstrap plan;upstream audit 在显式 `execute=true` 且 `useCodex=true` 时可运行 Codex,NAS Codex bootstrap 在显式 `execute=true` 时只返回目录准备、nvm 管理的 Node 22.14.0 / pnpm 10.28.2 / Codex CLI 安装计划,不复制 secrets、不写 systemd、不触发发布。 - 生成卡点固化记录:把超时、卡进程、远程命令误写、重复失败整理成“问题点 / 稳定解法 / 后续入口 / 验证证据”,避免原样重试。 - 生成改动文档同步计划:按变更文件自动提示需要同步的 README、API、AGENTS、docs、Obsidian、skill 和 ktWorkflow 入口。 - 生成多仓库提交/推送计划:按仓库分组、建议提交信息、列出提交和推送前检查。 @@ -114,7 +114,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login | `kt_napcat_sync_candidate_review` | 生成 NapCat sync candidate review 的 prompt/context/只读命令骨架,Task 5 不执行 Codex 或 Git 写操作 | | `kt_napcat_runtime_release_readiness` | 生成 NapCat runtime release readiness 的 prompt/context/只读检查骨架,不自动构建或发布 | | `kt_napcat_remote_dev_handoff` | 生成 NapCat 自动化远程开发 handoff 的 prompt/context 骨架,不创建线程或同步仓库 | -| `kt_nas_codex_bootstrap_plan` | 生成可信 NAS Codex bootstrap dry-run/execute command plan;execute 只规划目录准备和 CLI 包检查/安装,不复制 secrets、不写 systemd | +| `kt_nas_codex_bootstrap_plan` | 生成可信 NAS Codex bootstrap dry-run/execute command plan;execute 只规划目录准备和 nvm 管理的 Node/pnpm/Codex 安装,不复制 secrets、不写 systemd | | `kt_napcat_device_profile_check` | 静态检查 API NapCat 设备身份护栏,覆盖 hostname、MAC、`machine-info`、runtime dir 和 DB timezone | | `kt_blocker_resolution` | 生成或写入卡点固化记录,提醒停止原样重试 | | `kt_remote_health_check` | 生成或执行远程只读健康检查命令 | @@ -137,7 +137,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login | `pnpm run napcat-sync-candidate-review` | 输出 sync candidate review 的 prompt/context/只读命令骨架,不执行 Codex 或 Git 写操作。 | | `pnpm run napcat-runtime-release-readiness` | 输出 runtime release readiness 的 prompt/context/只读检查骨架,不构建镜像、不调用 kubectl、不发布。 | | `pnpm run napcat-remote-dev-handoff` | 输出远程开发 handoff 的 prompt/context 骨架,不创建线程、不同步仓库、不执行 Codex。 | -| `pnpm run nas-codex-bootstrap` | 输出可信 NAS Codex bootstrap dry-run plan;传 `--execute` 只生成目录准备和 CLI 包检查/安装命令计划,不真实执行 SSH、不复制 secrets、不写 systemd。 | +| `pnpm run nas-codex-bootstrap` | 输出可信 NAS Codex bootstrap dry-run plan;传 `--execute` 只生成目录准备和 nvm 管理的 Node/pnpm/Codex 安装命令计划,不真实执行 SSH、不复制 secrets、不写 systemd。 | | `pnpm run napcat-device-profile-check` | 静态检查 API NapCat 设备身份护栏,防止回退到未知设备风险配置。 | | `pnpm run deploy-observation` | 默认 dry-run 输出只读 NAS 观测命令;传 `--execute` 时执行 Jenkins/K8s/health/smoke 观测并写入 `.kt-workspace/test-artifacts/deploy-observation`。 | | `pnpm run obsidian-context` | 输出 Obsidian 索引上下文;可传 `--module Admin`、`--query QQBot`、`--max-documents 10`。 | diff --git a/src/selfTest.ts b/src/selfTest.ts index 10f6502..8283bd5 100644 --- a/src/selfTest.ts +++ b/src/selfTest.ts @@ -220,6 +220,10 @@ export async function runSelfTest(): Promise { throw new Error("NAS Codex bootstrap Windows path guard self-check failed"); } for (const expected of [ + "export NVM_DIR=/vol1/docker/kt-codex/runtime/nvm", + 'test -s "$NVM_DIR/nvm.sh"', + "nvm --version", + "nvm current", "node --version", "corepack --version", "pnpm --version", @@ -250,7 +254,13 @@ export async function runSelfTest(): Promise { } if ( !executeBootstrapCommandText.includes("install -d -m 700 /vol1/docker/kt-codex/home/.codex") || - !executeBootstrapCommandText.includes("npm install -g @openai/codex") + !executeBootstrapCommandText.includes("install -d -m 755 /vol1/docker/kt-codex/runtime") || + !executeBootstrapCommandText.includes("git clone https://github.com/nvm-sh/nvm.git \"$NVM_DIR\"") || + !executeBootstrapCommandText.includes("git -C \"$NVM_DIR\" checkout \"$NVM_TAG\"") || + !executeBootstrapCommandText.includes("nvm install \"$NODE_VERSION\"") || + !executeBootstrapCommandText.includes("nvm alias default \"$NODE_VERSION\"") || + !executeBootstrapCommandText.includes("npm install -g @openai/codex@latest") || + !executeBootstrapCommandText.includes("ln -sfn \"$target\" \"/usr/local/bin/$cmd\"") ) { throw new Error("NAS Codex bootstrap execute package plan self-check failed"); } @@ -434,7 +444,7 @@ export async function runSelfTest(): Promise { for (const expected of [ "CODEX_HOME='/vol1/docker/kt-codex/home/.codex'", "--cd '/vol1/docker/kt-codex/workspace/KT'", - "--profile-v2 automation", + "--profile automation", "--sandbox workspace-write", "--json", "--ephemeral", diff --git a/src/tools/napcatAutomation.ts b/src/tools/napcatAutomation.ts index fdf6bbc..9344a75 100644 --- a/src/tools/napcatAutomation.ts +++ b/src/tools/napcatAutomation.ts @@ -335,6 +335,9 @@ export function buildNapcatRemoteDevHandoff( interface NasCodexBootstrapContext { codexHome: string; + nodeVersion: string; + nvmDir: string; + nvmTag: string; serviceName: string; workspaceRoot: string; } @@ -354,6 +357,9 @@ export function buildNasCodexBootstrapPlan(input: NasCodexBootstrapPlanInput) { input.codexHome, napcatAutomationDefaults.codexHome, ), + nodeVersion: '22.14.0', + nvmDir: '/vol1/docker/kt-codex/runtime/nvm', + nvmTag: 'v0.40.5', serviceName: resolveNasBootstrapServiceName( input.serviceName ?? napcatAutomationDefaults.bootstrapServiceName, ), @@ -481,6 +487,11 @@ function buildNasBootstrapDryRunCommand( return buildNasBootstrapSshPlanCommand( [ "printf '%s\\n' '[ktWorkflow] NAS Codex bootstrap dry-run checks'", + `export NVM_DIR=${context.nvmDir}`, + 'test -s "$NVM_DIR/nvm.sh"', + '. "$NVM_DIR/nvm.sh"', + 'nvm --version', + 'nvm current', 'node --version', 'corepack --version', 'pnpm --version', @@ -504,23 +515,53 @@ function buildNasBootstrapExecuteCommand( context: NasCodexBootstrapContext, ): string { const workspaceParent = path.posix.dirname(context.workspaceRoot); + const nvmParent = path.posix.dirname(context.nvmDir); return buildNasBootstrapSshPlanCommand( [ "printf '%s\\n' '[ktWorkflow] NAS Codex bootstrap execute plan'", `install -d -m 755 ${workspaceParent}`, + `install -d -m 755 ${nvmParent}`, `install -d -m 700 ${context.codexHome}`, `install -d -m 755 ${napcatNasCodexArtifactRoot}`, - 'node --version', + `export NVM_DIR=${context.nvmDir}`, + `NVM_TAG=${context.nvmTag}`, + `NODE_VERSION=${context.nodeVersion}`, + 'if [ ! -d "$NVM_DIR/.git" ]; then', + ' git clone https://github.com/nvm-sh/nvm.git "$NVM_DIR"', + 'fi', + 'git -C "$NVM_DIR" fetch --tags origin', + 'git -C "$NVM_DIR" checkout "$NVM_TAG"', + '. "$NVM_DIR/nvm.sh"', + 'nvm install "$NODE_VERSION"', + 'nvm alias default "$NODE_VERSION"', + 'nvm use "$NODE_VERSION"', + 'npm config delete prefix >/dev/null 2>&1 || true', 'corepack --version', 'corepack enable', 'corepack prepare pnpm@10.28.2 --activate', 'pnpm --version', 'git --version', 'docker --version', - 'if ! command -v codex >/dev/null 2>&1; then', - ' npm install -g @openai/codex', + 'npm install -g @openai/codex@latest', + "cat >/etc/profile.d/kt-codex-nvm.sh <<'PROFILE'", + 'export NVM_DIR=/vol1/docker/kt-codex/runtime/nvm', + 'if [ -s "$NVM_DIR/nvm.sh" ]; then', + ' . "$NVM_DIR/nvm.sh"', + ' nvm use --silent default >/dev/null 2>&1 || true', 'fi', + 'if [ -s "$NVM_DIR/bash_completion" ]; then', + ' . "$NVM_DIR/bash_completion"', + 'fi', + 'PROFILE', + 'chmod 644 /etc/profile.d/kt-codex-nvm.sh', + 'for cmd in node npm npx corepack pnpm pnpx codex; do', + ' target=$(command -v "$cmd")', + ' ln -sfn "$target" "/usr/local/bin/$cmd"', + 'done', + 'nvm --version', + 'nvm current', + 'node --version', 'codex --version', `test -d ${context.workspaceRoot}`, `test -d ${context.codexHome}`, @@ -586,7 +627,7 @@ export function buildNapcatCodexExecCommand( `CODEX_HOME=${shellQuotePath(codexHome)}`, 'codex --ask-for-approval never exec', `--cd ${shellQuotePath(input.workspaceRoot)}`, - '--profile-v2 automation', + '--profile automation', '--sandbox workspace-write', '--json', '--ephemeral',