From fc750ddcf1a4bc5aa977faf12dc17c66415c472e Mon Sep 17 00:00:00 2001 From: sunlei Date: Thu, 25 Jun 2026 01:52:13 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=AF=B9=E9=BD=90NapCat=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=8C=96=E5=85=A5=E5=8F=A3=E9=BB=98=E8=AE=A4=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 + package.json | 1 + src/registerTools.ts | 69 ++++++++++++---------- src/selfTest.ts | 108 ++++++++++++++++++++++++++++++++++ src/tools/napcatAutomation.ts | 78 ++++++++++++++---------- 5 files changed, 194 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 141b678..8720c62 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,7 @@ pnpm run workstream-closeout -- --title "发布闭环" --verification "Jenkins S pnpm run napcat-upstream-audit -- --artifact-root .kt-workspace/test-artifacts/napcat-upstream-sync pnpm run napcat-sync-candidate-review pnpm run napcat-runtime-release-readiness +pnpm run napcat-remote-dev-handoff pnpm run nas-codex-bootstrap pnpm run napcat-device-profile-check pnpm run cleanup-history -- --dry-run @@ -126,6 +127,7 @@ pnpm run admin-login -- --url http://127.0.0.1:5999/#/auth/login | `pnpm run napcat-upstream-audit` | 默认 dry-run 输出 NapCatQQ 上游 release 审计分类、只读 Git 命令和 artifact 路径;显式 `--execute --use-codex` 才运行 Codex。 | | `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;真实安装、同步和 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`。 | diff --git a/package.json b/package.json index a592dfa..97563c0 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "deploy-observation": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --deploy-observation", "global-review": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --global-review", "napcat-device-profile-check": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-device-profile-check", + "napcat-remote-dev-handoff": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-remote-dev-handoff", "napcat-runtime-release-readiness": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-runtime-release-readiness", "napcat-sync-candidate-review": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-sync-candidate-review", "napcat-upstream-audit": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-upstream-audit", diff --git a/src/registerTools.ts b/src/registerTools.ts index cbb66c9..8e18e27 100644 --- a/src/registerTools.ts +++ b/src/registerTools.ts @@ -28,6 +28,7 @@ import { buildNapcatSyncCandidateReview, buildNapcatUpstreamAudit, buildNasCodexBootstrapPlan, + napcatAutomationDefaults, } from './tools/napcatAutomation.js'; import { buildCommitPlan, buildComponentWorkflow, buildDbSyncPlan, buildFinishTask, buildPushPlan, buildRemoteHealthCheck } from './tools/workflow.js'; import { workstreamReusablePatternValues } from './core/constants.js'; @@ -395,16 +396,18 @@ export function registerTools(server: McpServer): void { createCandidateBranch: z.boolean().default(false), dryMergeConflict: z.boolean().default(false), execute: z.boolean().default(false), - forkBranch: z.string().default('HEAD'), + forkBranch: z.string().default(napcatAutomationDefaults.forkBranch), forkPatchFiles: z.array(z.string()).default([]), - forkRepo: z.string().default('KTeam/NapCatQQ'), - lastAcceptedUpstreamBase: z.string().default('origin/main'), + forkRepo: z.string().default(napcatAutomationDefaults.forkRepo), + lastAcceptedUpstreamBase: z + .string() + .default(napcatAutomationDefaults.lastAcceptedUpstreamBase), outputSchemaPath: z.string().optional(), upstreamChangedFiles: z.array(z.string()).default([]), - upstreamReleaseTag: z.string().default('upstream/main'), - upstreamRepo: z.string().default('NapNeko/NapCatQQ'), + upstreamReleaseTag: z.string().default(napcatAutomationDefaults.upstreamReleaseRef), + upstreamRepo: z.string().default(napcatAutomationDefaults.upstreamRepo), useCodex: z.boolean().default(false), - workspaceRoot: z.string().default('/vol1/docker/kt-codex/workspace/KT'), + workspaceRoot: z.string().default(napcatAutomationDefaults.workspaceRoot), }, title: 'KT NapCat Upstream Audit', }, @@ -420,15 +423,17 @@ export function registerTools(server: McpServer): void { artifactRoot: z .string() .default('.kt-workspace/test-artifacts/napcat-automation/sync-candidate-review'), - candidateBranch: z.string().default('napcat-upstream-sync/candidate'), + candidateBranch: z.string().default(napcatAutomationDefaults.candidateBranch), execute: z.boolean().default(false), - forkBranch: z.string().default('dev'), - forkRepo: z.string().default('KTeam/NapCatQQ'), - lastAcceptedUpstreamBase: z.string().default('origin/main'), - upstreamReleaseTag: z.string().default('upstream/main'), - upstreamRepo: z.string().default('NapNeko/NapCatQQ'), + forkBranch: z.string().default(napcatAutomationDefaults.forkBranch), + forkRepo: z.string().default(napcatAutomationDefaults.forkRepo), + lastAcceptedUpstreamBase: z + .string() + .default(napcatAutomationDefaults.lastAcceptedUpstreamBase), + upstreamReleaseTag: z.string().default(napcatAutomationDefaults.upstreamReleaseRef), + upstreamRepo: z.string().default(napcatAutomationDefaults.upstreamRepo), useCodex: z.boolean().default(false), - workspaceRoot: z.string().default('/vol1/docker/kt-codex/workspace/KT'), + workspaceRoot: z.string().default(napcatAutomationDefaults.workspaceRoot), }, title: 'KT NapCat Sync Candidate Review', }, @@ -441,20 +446,20 @@ export function registerTools(server: McpServer): void { description: '生成 NapCat runtime release readiness dry-run prompt、上下文和只读检查骨架;不自动构建镜像、不调用 kubectl、不发布。', inputSchema: { - apiImageTag: z.string().default('main-'), + apiImageTag: z.string().default(napcatAutomationDefaults.apiImageTag), artifactRoot: z .string() .default('.kt-workspace/test-artifacts/napcat-automation/runtime-release-readiness'), - candidateBranch: z.string().default('napcat-upstream-sync/candidate'), + candidateBranch: z.string().default(napcatAutomationDefaults.candidateBranch), execute: z.boolean().default(false), - forkBranch: z.string().default('dev'), - forkRepo: z.string().default('KTeam/NapCatQQ'), - napcatImageTag: z.string().default('kt-napcat-desktop-cn:desktop-cn'), - profile: z.string().default('desktop-cn'), - upstreamReleaseTag: z.string().default('upstream/main'), - upstreamRepo: z.string().default('NapNeko/NapCatQQ'), + forkBranch: z.string().default(napcatAutomationDefaults.forkBranch), + forkRepo: z.string().default(napcatAutomationDefaults.forkRepo), + napcatImageTag: z.string().default(napcatAutomationDefaults.runtimeImageTag), + profile: z.string().default(napcatAutomationDefaults.runtimeProfile), + upstreamReleaseTag: z.string().default(napcatAutomationDefaults.upstreamReleaseRef), + upstreamRepo: z.string().default(napcatAutomationDefaults.upstreamRepo), useCodex: z.boolean().default(false), - workspaceRoot: z.string().default('/vol1/docker/kt-codex/workspace/KT'), + workspaceRoot: z.string().default(napcatAutomationDefaults.workspaceRoot), }, title: 'KT NapCat Runtime Release Readiness', }, @@ -470,15 +475,15 @@ export function registerTools(server: McpServer): void { artifactRoot: z .string() .default('.kt-workspace/test-artifacts/napcat-automation/remote-dev-handoff'), - candidateBranch: z.string().default('napcat-upstream-sync/candidate'), + candidateBranch: z.string().default(napcatAutomationDefaults.candidateBranch), execute: z.boolean().default(false), - forkBranch: z.string().default('dev'), - forkRepo: z.string().default('KTeam/NapCatQQ'), - targetHost: z.string().default('nas'), - upstreamReleaseTag: z.string().default('upstream/main'), - upstreamRepo: z.string().default('NapNeko/NapCatQQ'), + forkBranch: z.string().default(napcatAutomationDefaults.forkBranch), + forkRepo: z.string().default(napcatAutomationDefaults.forkRepo), + targetHost: z.string().default(napcatAutomationDefaults.targetHost), + upstreamReleaseTag: z.string().default(napcatAutomationDefaults.upstreamReleaseRef), + upstreamRepo: z.string().default(napcatAutomationDefaults.upstreamRepo), useCodex: z.boolean().default(false), - workspaceRoot: z.string().default('/vol1/docker/kt-codex/workspace/KT'), + workspaceRoot: z.string().default(napcatAutomationDefaults.workspaceRoot), }, title: 'KT NapCat Remote Dev Handoff', }, @@ -494,10 +499,10 @@ export function registerTools(server: McpServer): void { artifactRoot: z .string() .default('.kt-workspace/test-artifacts/napcat-automation/nas-codex-bootstrap'), - codexHome: z.string().default('/vol1/docker/kt-codex/home/.codex'), + codexHome: z.string().default(napcatAutomationDefaults.codexHome), execute: z.boolean().default(false), - serviceName: z.string().default('kt-codex-automation'), - workspaceRoot: z.string().default('/vol1/docker/kt-codex/workspace/KT'), + serviceName: z.string().default(napcatAutomationDefaults.bootstrapServiceName), + workspaceRoot: z.string().default(napcatAutomationDefaults.workspaceRoot), }, title: 'KT NAS Codex Bootstrap Plan', }, diff --git a/src/selfTest.ts b/src/selfTest.ts index e5070b8..57ae8ec 100644 --- a/src/selfTest.ts +++ b/src/selfTest.ts @@ -5,6 +5,7 @@ import { parseNasCodexBootstrapCliArgs, parseDeployObservationCliArgs, parseGlobalReviewCliArgs, + parseNapcatRemoteDevHandoffCliArgs, parseNapcatRuntimeReleaseReadinessCliArgs, parseNapcatSyncCandidateReviewCliArgs, parseNapcatUpstreamAuditCliArgs, @@ -46,9 +47,15 @@ import { } from "./tools/napcatAutomation.types.js"; import { buildNapcatCodexExecCommand, + buildNapcatRemoteDevHandoff, + buildNapcatRuntimeReleaseReadiness, + buildNapcatSyncCandidateReview, buildNapcatUpstreamAudit, + buildNasCodexBootstrapPlan, classifyNapcatUpstreamAudit, + napcatAutomationDefaults, } from "./tools/napcatAutomation.js"; +import { registerTools } from "./registerTools.js"; import { loadNapcatAutomationPrompt, type NapcatAutomationPromptName, @@ -128,6 +135,11 @@ export async function runSelfTest(): Promise { "server", "--napcat-runtime-release-readiness", ]); + const napcatRemoteHandoffCli = parseNapcatRemoteDevHandoffCliArgs([ + "node", + "server", + "--napcat-remote-dev-handoff", + ]); const nasBootstrapCli = parseNasCodexBootstrapCliArgs([ "node", "server", @@ -136,10 +148,85 @@ export async function runSelfTest(): Promise { if ( napcatCandidateCli.execute || napcatRuntimeCli.execute || + napcatRemoteHandoffCli.execute || nasBootstrapCli.execute ) { throw new Error("NapCat auxiliary CLI dry-run default self-check failed"); } + const napcatCandidateDefaults = buildNapcatSyncCandidateReview({}).context; + const napcatRuntimeDefaults = buildNapcatRuntimeReleaseReadiness({}).context; + const napcatRemoteDefaults = buildNapcatRemoteDevHandoff({}).context; + const nasBootstrapDefaults = buildNasCodexBootstrapPlan({}).context; + if ( + napcatCandidateDefaults.candidateBranch !== + napcatAutomationDefaults.candidateBranch || + napcatCandidateDefaults.forkBranch !== napcatAutomationDefaults.forkBranch || + napcatCandidateDefaults.forkRepo !== napcatAutomationDefaults.forkRepo || + napcatCandidateDefaults.lastAcceptedUpstreamBase !== + napcatAutomationDefaults.lastAcceptedUpstreamBase || + napcatCandidateDefaults.upstreamReleaseTag !== + napcatAutomationDefaults.upstreamReleaseRef || + napcatCandidateDefaults.upstreamRepo !== napcatAutomationDefaults.upstreamRepo || + napcatCandidateDefaults.workspaceRoot !== + napcatAutomationDefaults.workspaceRoot + ) { + throw new Error("NapCat candidate review default alignment self-check failed"); + } + if ( + napcatRuntimeDefaults.apiImageTag !== + napcatAutomationDefaults.apiImageTag || + napcatRuntimeDefaults.candidateBranch !== + napcatAutomationDefaults.candidateBranch || + napcatRuntimeDefaults.forkBranch !== napcatAutomationDefaults.forkBranch || + napcatRuntimeDefaults.forkRepo !== napcatAutomationDefaults.forkRepo || + napcatRuntimeDefaults.napcatImageTag !== + napcatAutomationDefaults.runtimeImageTag || + napcatRuntimeDefaults.profile !== napcatAutomationDefaults.runtimeProfile || + napcatRuntimeDefaults.upstreamReleaseTag !== + napcatAutomationDefaults.upstreamReleaseRef || + napcatRuntimeDefaults.workspaceRoot !== + napcatAutomationDefaults.workspaceRoot + ) { + throw new Error("NapCat runtime readiness default alignment self-check failed"); + } + if ( + napcatRemoteDefaults.candidateBranch !== + napcatAutomationDefaults.candidateBranch || + napcatRemoteDefaults.forkBranch !== napcatAutomationDefaults.forkBranch || + napcatRemoteDefaults.forkRepo !== napcatAutomationDefaults.forkRepo || + napcatRemoteDefaults.targetHost !== napcatAutomationDefaults.targetHost || + napcatRemoteDefaults.upstreamReleaseTag !== + napcatAutomationDefaults.upstreamReleaseRef || + napcatRemoteDefaults.workspaceRoot !== napcatAutomationDefaults.workspaceRoot + ) { + throw new Error("NapCat remote handoff default alignment self-check failed"); + } + if ( + nasBootstrapDefaults.codexHome !== napcatAutomationDefaults.codexHome || + nasBootstrapDefaults.serviceName !== + napcatAutomationDefaults.bootstrapServiceName || + nasBootstrapDefaults.workspaceRoot !== napcatAutomationDefaults.workspaceRoot + ) { + throw new Error("NAS Codex bootstrap default alignment self-check failed"); + } + const packageJson = JSON.parse( + readFileSync(resolveInsideRoot("mcp/ktWorkflow/package.json"), "utf8"), + ) as { scripts?: Record }; + if (!packageJson.scripts?.["napcat-remote-dev-handoff"]) { + throw new Error("NapCat remote handoff npm script self-check failed"); + } + const registeredByFakeServer: string[] = []; + const fakeMcpServer = { + /** + * Records registered MCP tool names so self-test proves the actual registerTools surface, not only the constants list. + * @param name - MCP tool name passed by `registerTools`. + * @returns Nothing; the name is appended to `registeredByFakeServer`. + */ + registerTool(name: string): void { + registeredByFakeServer.push(name); + }, + }; + registerTools(fakeMcpServer as never); for (const toolName of [ "kt_napcat_upstream_audit", "kt_napcat_sync_candidate_review", @@ -150,6 +237,9 @@ export async function runSelfTest(): Promise { if (!registeredToolNames.includes(toolName)) { throw new Error(`NapCat MCP tool registry self-check failed: ${toolName}`); } + if (!registeredByFakeServer.includes(toolName)) { + throw new Error(`NapCat MCP registerTools self-check failed: ${toolName}`); + } } if (parseNapcatAutomationClassification("manual-review") !== "manual-review") { throw new Error("NapCat classification parser self-check failed"); @@ -175,6 +265,24 @@ export async function runSelfTest(): Promise { "NapCat upstream audit dry-run artifact plan self-check failed", ); } + const dryRunAuditDefaultCommands = dryRunAudit.commands.map( + (item) => item.command, + ); + if ( + dryRunAuditDefaultCommands.some((command) => + command.includes("FORK_BRANCH:-HEAD"), + ) || + !dryRunAuditDefaultCommands.some((command) => + command.includes(`FORK_BRANCH:-${napcatAutomationDefaults.forkBranch}`), + ) || + !dryRunAuditDefaultCommands.some((command) => + command.includes( + `UPSTREAM_RELEASE_REF:-${napcatAutomationDefaults.upstreamReleaseRef}`, + ), + ) + ) { + throw new Error("NapCat upstream audit command default alignment self-check failed"); + } const codexCommand = buildNapcatCodexExecCommand({ artifactRoot: "/vol1/docker/kt-codex/artifacts/smoke", contextPacketPath: diff --git a/src/tools/napcatAutomation.ts b/src/tools/napcatAutomation.ts index 31fd767..bcea7c5 100644 --- a/src/tools/napcatAutomation.ts +++ b/src/tools/napcatAutomation.ts @@ -100,10 +100,22 @@ const napcatNasCodexArtifactRoot = '/vol1/docker/kt-codex/artifacts'; const napcatLocalArtifactRoot = '.kt-workspace/test-artifacts'; const napcatAutomationSkeletonArtifactRoot = '.kt-workspace/test-artifacts/napcat-automation'; -const defaultNapcatForkRepo = 'KTeam/NapCatQQ'; -const defaultNapcatUpstreamRepo = 'NapNeko/NapCatQQ'; -const defaultNapcatCandidateBranch = 'napcat-upstream-sync/candidate'; -const defaultNapcatWorkspaceRoot = '/vol1/docker/kt-codex/workspace/KT'; + +export const napcatAutomationDefaults = { + apiImageTag: 'main-', + bootstrapServiceName: 'kt-codex-automation', + candidateBranch: 'napcat-upstream-sync/candidate', + codexHome: '/vol1/docker/kt-codex/home/.codex', + forkBranch: 'dev', + forkRepo: 'KTeam/NapCatQQ', + lastAcceptedUpstreamBase: 'origin/main', + runtimeImageTag: 'kt-napcat-desktop-cn:desktop-cn', + runtimeProfile: 'desktop-cn', + targetHost: 'nas', + upstreamReleaseRef: 'upstream/main', + upstreamRepo: 'NapNeko/NapCatQQ', + workspaceRoot: '/vol1/docker/kt-codex/workspace/KT', +} as const; interface NapcatPromptSkeletonConfig { artifactSlug: string; @@ -189,14 +201,14 @@ export function buildNapcatSyncCandidateReview( input: NapcatSyncCandidateReviewInput, ) { const context = { - candidateBranch: input.candidateBranch ?? defaultNapcatCandidateBranch, - forkBranch: input.forkBranch ?? 'dev', - forkRepo: input.forkRepo ?? defaultNapcatForkRepo, + candidateBranch: input.candidateBranch ?? napcatAutomationDefaults.candidateBranch, + forkBranch: input.forkBranch ?? napcatAutomationDefaults.forkBranch, + forkRepo: input.forkRepo ?? napcatAutomationDefaults.forkRepo, lastAcceptedUpstreamBase: - input.lastAcceptedUpstreamBase ?? 'LAST_ACCEPTED_UPSTREAM_BASE', - upstreamReleaseTag: input.upstreamReleaseTag ?? 'UPSTREAM_RELEASE_REF', - upstreamRepo: input.upstreamRepo ?? defaultNapcatUpstreamRepo, - workspaceRoot: input.workspaceRoot ?? defaultNapcatWorkspaceRoot, + input.lastAcceptedUpstreamBase ?? napcatAutomationDefaults.lastAcceptedUpstreamBase, + upstreamReleaseTag: input.upstreamReleaseTag ?? napcatAutomationDefaults.upstreamReleaseRef, + upstreamRepo: input.upstreamRepo ?? napcatAutomationDefaults.upstreamRepo, + workspaceRoot: input.workspaceRoot ?? napcatAutomationDefaults.workspaceRoot, }; return buildNapcatPromptSkeleton({ @@ -209,13 +221,13 @@ export function buildNapcatSyncCandidateReview( }, { command: - 'git log --oneline --decorate -n 20 "${CANDIDATE_BRANCH:-napcat-upstream-sync/candidate}"', + `git log --oneline --decorate -n 20 "\${CANDIDATE_BRANCH:-${napcatAutomationDefaults.candidateBranch}}"`, description: 'Inspect recent candidate commits without changing refs.', readOnly: true, }, { command: - 'git diff --stat "${LAST_ACCEPTED_UPSTREAM_BASE:-origin/main}..${CANDIDATE_BRANCH:-napcat-upstream-sync/candidate}"', + `git diff --stat "\${LAST_ACCEPTED_UPSTREAM_BASE:-${napcatAutomationDefaults.lastAcceptedUpstreamBase}}..\${CANDIDATE_BRANCH:-${napcatAutomationDefaults.candidateBranch}}"`, description: 'Summarize candidate file churn for human review.', readOnly: true, }, @@ -239,13 +251,14 @@ export function buildNapcatRuntimeReleaseReadiness( input: NapcatRuntimeReleaseReadinessInput, ) { const context = { - apiImageTag: input.apiImageTag ?? 'main-', - candidateBranch: input.candidateBranch ?? defaultNapcatCandidateBranch, - forkRepo: input.forkRepo ?? defaultNapcatForkRepo, - napcatImageTag: input.napcatImageTag ?? 'kt-napcat-desktop-cn:', - profile: input.profile ?? 'desktop-cn', - upstreamReleaseTag: input.upstreamReleaseTag ?? 'UPSTREAM_RELEASE_REF', - workspaceRoot: input.workspaceRoot ?? defaultNapcatWorkspaceRoot, + apiImageTag: input.apiImageTag ?? napcatAutomationDefaults.apiImageTag, + candidateBranch: input.candidateBranch ?? napcatAutomationDefaults.candidateBranch, + forkBranch: input.forkBranch ?? napcatAutomationDefaults.forkBranch, + forkRepo: input.forkRepo ?? napcatAutomationDefaults.forkRepo, + napcatImageTag: input.napcatImageTag ?? napcatAutomationDefaults.runtimeImageTag, + profile: input.profile ?? napcatAutomationDefaults.runtimeProfile, + upstreamReleaseTag: input.upstreamReleaseTag ?? napcatAutomationDefaults.upstreamReleaseRef, + workspaceRoot: input.workspaceRoot ?? napcatAutomationDefaults.workspaceRoot, }; return buildNapcatPromptSkeleton({ @@ -288,11 +301,12 @@ export function buildNapcatRemoteDevHandoff( input: NapcatRemoteDevHandoffInput, ) { const context = { - candidateBranch: input.candidateBranch ?? defaultNapcatCandidateBranch, - forkRepo: input.forkRepo ?? defaultNapcatForkRepo, - targetHost: input.targetHost ?? 'nas', - upstreamReleaseTag: input.upstreamReleaseTag ?? 'UPSTREAM_RELEASE_REF', - workspaceRoot: input.workspaceRoot ?? defaultNapcatWorkspaceRoot, + candidateBranch: input.candidateBranch ?? napcatAutomationDefaults.candidateBranch, + forkBranch: input.forkBranch ?? napcatAutomationDefaults.forkBranch, + forkRepo: input.forkRepo ?? napcatAutomationDefaults.forkRepo, + targetHost: input.targetHost ?? napcatAutomationDefaults.targetHost, + upstreamReleaseTag: input.upstreamReleaseTag ?? napcatAutomationDefaults.upstreamReleaseRef, + workspaceRoot: input.workspaceRoot ?? napcatAutomationDefaults.workspaceRoot, }; return buildNapcatPromptSkeleton({ @@ -329,9 +343,9 @@ export function buildNasCodexBootstrapPlan(input: NasCodexBootstrapPlanInput) { input.artifactRoot?.trim() || `${napcatAutomationSkeletonArtifactRoot}/nas-codex-bootstrap`; const context = { - codexHome: input.codexHome ?? '/vol1/docker/kt-codex/home/.codex', - serviceName: input.serviceName ?? 'kt-codex-automation', - workspaceRoot: input.workspaceRoot ?? defaultNapcatWorkspaceRoot, + codexHome: input.codexHome ?? napcatAutomationDefaults.codexHome, + serviceName: input.serviceName ?? napcatAutomationDefaults.bootstrapServiceName, + workspaceRoot: input.workspaceRoot ?? napcatAutomationDefaults.workspaceRoot, }; const requestedExecute = input.execute === true; @@ -532,7 +546,7 @@ function assertSafeNapcatCodexArtifactRoot(artifactRoot: string): void { * @returns The configured workspace root or the stabilized NAS kt-codex workspace path. */ function resolveNapcatCodexWorkspaceRoot(workspaceRoot?: string): string { - return workspaceRoot?.trim() || '/vol1/docker/kt-codex/workspace/KT'; + return workspaceRoot?.trim() || napcatAutomationDefaults.workspaceRoot; } /** @@ -1028,19 +1042,19 @@ export function buildNapcatUpstreamAudit( }, { command: - 'git diff --name-only "${LAST_ACCEPTED_UPSTREAM_BASE:-origin/main}..${UPSTREAM_RELEASE_REF:-upstream/main}"', + `git diff --name-only "\${LAST_ACCEPTED_UPSTREAM_BASE:-${napcatAutomationDefaults.lastAcceptedUpstreamBase}}..\${UPSTREAM_RELEASE_REF:-${napcatAutomationDefaults.upstreamReleaseRef}}"`, description: 'List upstream release files changed since the last accepted base.', readOnly: true, }, { command: - 'git diff --name-only "${LAST_ACCEPTED_UPSTREAM_BASE:-origin/main}..HEAD"', + `git diff --name-only "\${LAST_ACCEPTED_UPSTREAM_BASE:-${napcatAutomationDefaults.lastAcceptedUpstreamBase}}..\${FORK_BRANCH:-${napcatAutomationDefaults.forkBranch}}"`, description: 'List KT fork patch files for deterministic overlap checks.', readOnly: true, }, { command: - 'git merge-tree "${FORK_BRANCH:-HEAD}" "${UPSTREAM_RELEASE_REF:-upstream/main}"', + `git merge-tree "\${FORK_BRANCH:-${napcatAutomationDefaults.forkBranch}}" "\${UPSTREAM_RELEASE_REF:-${napcatAutomationDefaults.upstreamReleaseRef}}"`, description: 'Probe the dry merge shape without updating the worktree or refs.', readOnly: true, },