fix: 对齐NapCat自动化入口默认值

This commit is contained in:
sunlei 2026-06-25 01:52:13 +08:00
parent 6fc5e65986
commit fc750ddcf1
5 changed files with 194 additions and 64 deletions

View File

@ -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-upstream-audit -- --artifact-root .kt-workspace/test-artifacts/napcat-upstream-sync
pnpm run napcat-sync-candidate-review pnpm run napcat-sync-candidate-review
pnpm run napcat-runtime-release-readiness pnpm run napcat-runtime-release-readiness
pnpm run napcat-remote-dev-handoff
pnpm run nas-codex-bootstrap pnpm run nas-codex-bootstrap
pnpm run napcat-device-profile-check pnpm run napcat-device-profile-check
pnpm run cleanup-history -- --dry-run 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-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-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-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 nas-codex-bootstrap` | 输出可信 NAS Codex bootstrap dry-run plan真实安装、同步和 systemd 接入留给后续实现。 |
| `pnpm run napcat-device-profile-check` | 静态检查 API NapCat 设备身份护栏,防止回退到未知设备风险配置。 | | `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 deploy-observation` | 默认 dry-run 输出只读 NAS 观测命令;传 `--execute` 时执行 Jenkins/K8s/health/smoke 观测并写入 `.kt-workspace/test-artifacts/deploy-observation`。 |

View File

@ -10,6 +10,7 @@
"deploy-observation": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --deploy-observation", "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", "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-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-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-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", "napcat-upstream-audit": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-upstream-audit",

View File

@ -28,6 +28,7 @@ import {
buildNapcatSyncCandidateReview, buildNapcatSyncCandidateReview,
buildNapcatUpstreamAudit, buildNapcatUpstreamAudit,
buildNasCodexBootstrapPlan, buildNasCodexBootstrapPlan,
napcatAutomationDefaults,
} from './tools/napcatAutomation.js'; } from './tools/napcatAutomation.js';
import { buildCommitPlan, buildComponentWorkflow, buildDbSyncPlan, buildFinishTask, buildPushPlan, buildRemoteHealthCheck } from './tools/workflow.js'; import { buildCommitPlan, buildComponentWorkflow, buildDbSyncPlan, buildFinishTask, buildPushPlan, buildRemoteHealthCheck } from './tools/workflow.js';
import { workstreamReusablePatternValues } from './core/constants.js'; import { workstreamReusablePatternValues } from './core/constants.js';
@ -395,16 +396,18 @@ export function registerTools(server: McpServer): void {
createCandidateBranch: z.boolean().default(false), createCandidateBranch: z.boolean().default(false),
dryMergeConflict: z.boolean().default(false), dryMergeConflict: z.boolean().default(false),
execute: 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([]), forkPatchFiles: z.array(z.string()).default([]),
forkRepo: z.string().default('KTeam/NapCatQQ'), forkRepo: z.string().default(napcatAutomationDefaults.forkRepo),
lastAcceptedUpstreamBase: z.string().default('origin/main'), lastAcceptedUpstreamBase: z
.string()
.default(napcatAutomationDefaults.lastAcceptedUpstreamBase),
outputSchemaPath: z.string().optional(), outputSchemaPath: z.string().optional(),
upstreamChangedFiles: z.array(z.string()).default([]), upstreamChangedFiles: z.array(z.string()).default([]),
upstreamReleaseTag: z.string().default('upstream/main'), upstreamReleaseTag: z.string().default(napcatAutomationDefaults.upstreamReleaseRef),
upstreamRepo: z.string().default('NapNeko/NapCatQQ'), upstreamRepo: z.string().default(napcatAutomationDefaults.upstreamRepo),
useCodex: z.boolean().default(false), 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', title: 'KT NapCat Upstream Audit',
}, },
@ -420,15 +423,17 @@ export function registerTools(server: McpServer): void {
artifactRoot: z artifactRoot: z
.string() .string()
.default('.kt-workspace/test-artifacts/napcat-automation/sync-candidate-review'), .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), execute: z.boolean().default(false),
forkBranch: z.string().default('dev'), forkBranch: z.string().default(napcatAutomationDefaults.forkBranch),
forkRepo: z.string().default('KTeam/NapCatQQ'), forkRepo: z.string().default(napcatAutomationDefaults.forkRepo),
lastAcceptedUpstreamBase: z.string().default('origin/main'), lastAcceptedUpstreamBase: z
upstreamReleaseTag: z.string().default('upstream/main'), .string()
upstreamRepo: z.string().default('NapNeko/NapCatQQ'), .default(napcatAutomationDefaults.lastAcceptedUpstreamBase),
upstreamReleaseTag: z.string().default(napcatAutomationDefaults.upstreamReleaseRef),
upstreamRepo: z.string().default(napcatAutomationDefaults.upstreamRepo),
useCodex: z.boolean().default(false), 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', title: 'KT NapCat Sync Candidate Review',
}, },
@ -441,20 +446,20 @@ export function registerTools(server: McpServer): void {
description: description:
'生成 NapCat runtime release readiness dry-run prompt、上下文和只读检查骨架不自动构建镜像、不调用 kubectl、不发布。', '生成 NapCat runtime release readiness dry-run prompt、上下文和只读检查骨架不自动构建镜像、不调用 kubectl、不发布。',
inputSchema: { inputSchema: {
apiImageTag: z.string().default('main-<jenkins-build>'), apiImageTag: z.string().default(napcatAutomationDefaults.apiImageTag),
artifactRoot: z artifactRoot: z
.string() .string()
.default('.kt-workspace/test-artifacts/napcat-automation/runtime-release-readiness'), .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), execute: z.boolean().default(false),
forkBranch: z.string().default('dev'), forkBranch: z.string().default(napcatAutomationDefaults.forkBranch),
forkRepo: z.string().default('KTeam/NapCatQQ'), forkRepo: z.string().default(napcatAutomationDefaults.forkRepo),
napcatImageTag: z.string().default('kt-napcat-desktop-cn:desktop-cn'), napcatImageTag: z.string().default(napcatAutomationDefaults.runtimeImageTag),
profile: z.string().default('desktop-cn'), profile: z.string().default(napcatAutomationDefaults.runtimeProfile),
upstreamReleaseTag: z.string().default('upstream/main'), upstreamReleaseTag: z.string().default(napcatAutomationDefaults.upstreamReleaseRef),
upstreamRepo: z.string().default('NapNeko/NapCatQQ'), upstreamRepo: z.string().default(napcatAutomationDefaults.upstreamRepo),
useCodex: z.boolean().default(false), 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', title: 'KT NapCat Runtime Release Readiness',
}, },
@ -470,15 +475,15 @@ export function registerTools(server: McpServer): void {
artifactRoot: z artifactRoot: z
.string() .string()
.default('.kt-workspace/test-artifacts/napcat-automation/remote-dev-handoff'), .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), execute: z.boolean().default(false),
forkBranch: z.string().default('dev'), forkBranch: z.string().default(napcatAutomationDefaults.forkBranch),
forkRepo: z.string().default('KTeam/NapCatQQ'), forkRepo: z.string().default(napcatAutomationDefaults.forkRepo),
targetHost: z.string().default('nas'), targetHost: z.string().default(napcatAutomationDefaults.targetHost),
upstreamReleaseTag: z.string().default('upstream/main'), upstreamReleaseTag: z.string().default(napcatAutomationDefaults.upstreamReleaseRef),
upstreamRepo: z.string().default('NapNeko/NapCatQQ'), upstreamRepo: z.string().default(napcatAutomationDefaults.upstreamRepo),
useCodex: z.boolean().default(false), 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', title: 'KT NapCat Remote Dev Handoff',
}, },
@ -494,10 +499,10 @@ export function registerTools(server: McpServer): void {
artifactRoot: z artifactRoot: z
.string() .string()
.default('.kt-workspace/test-artifacts/napcat-automation/nas-codex-bootstrap'), .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), execute: z.boolean().default(false),
serviceName: z.string().default('kt-codex-automation'), serviceName: z.string().default(napcatAutomationDefaults.bootstrapServiceName),
workspaceRoot: z.string().default('/vol1/docker/kt-codex/workspace/KT'), workspaceRoot: z.string().default(napcatAutomationDefaults.workspaceRoot),
}, },
title: 'KT NAS Codex Bootstrap Plan', title: 'KT NAS Codex Bootstrap Plan',
}, },

View File

@ -5,6 +5,7 @@ import {
parseNasCodexBootstrapCliArgs, parseNasCodexBootstrapCliArgs,
parseDeployObservationCliArgs, parseDeployObservationCliArgs,
parseGlobalReviewCliArgs, parseGlobalReviewCliArgs,
parseNapcatRemoteDevHandoffCliArgs,
parseNapcatRuntimeReleaseReadinessCliArgs, parseNapcatRuntimeReleaseReadinessCliArgs,
parseNapcatSyncCandidateReviewCliArgs, parseNapcatSyncCandidateReviewCliArgs,
parseNapcatUpstreamAuditCliArgs, parseNapcatUpstreamAuditCliArgs,
@ -46,9 +47,15 @@ import {
} from "./tools/napcatAutomation.types.js"; } from "./tools/napcatAutomation.types.js";
import { import {
buildNapcatCodexExecCommand, buildNapcatCodexExecCommand,
buildNapcatRemoteDevHandoff,
buildNapcatRuntimeReleaseReadiness,
buildNapcatSyncCandidateReview,
buildNapcatUpstreamAudit, buildNapcatUpstreamAudit,
buildNasCodexBootstrapPlan,
classifyNapcatUpstreamAudit, classifyNapcatUpstreamAudit,
napcatAutomationDefaults,
} from "./tools/napcatAutomation.js"; } from "./tools/napcatAutomation.js";
import { registerTools } from "./registerTools.js";
import { import {
loadNapcatAutomationPrompt, loadNapcatAutomationPrompt,
type NapcatAutomationPromptName, type NapcatAutomationPromptName,
@ -128,6 +135,11 @@ export async function runSelfTest(): Promise<void> {
"server", "server",
"--napcat-runtime-release-readiness", "--napcat-runtime-release-readiness",
]); ]);
const napcatRemoteHandoffCli = parseNapcatRemoteDevHandoffCliArgs([
"node",
"server",
"--napcat-remote-dev-handoff",
]);
const nasBootstrapCli = parseNasCodexBootstrapCliArgs([ const nasBootstrapCli = parseNasCodexBootstrapCliArgs([
"node", "node",
"server", "server",
@ -136,10 +148,85 @@ export async function runSelfTest(): Promise<void> {
if ( if (
napcatCandidateCli.execute || napcatCandidateCli.execute ||
napcatRuntimeCli.execute || napcatRuntimeCli.execute ||
napcatRemoteHandoffCli.execute ||
nasBootstrapCli.execute nasBootstrapCli.execute
) { ) {
throw new Error("NapCat auxiliary CLI dry-run default self-check failed"); 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<string, string> };
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 [ for (const toolName of [
"kt_napcat_upstream_audit", "kt_napcat_upstream_audit",
"kt_napcat_sync_candidate_review", "kt_napcat_sync_candidate_review",
@ -150,6 +237,9 @@ export async function runSelfTest(): Promise<void> {
if (!registeredToolNames.includes(toolName)) { if (!registeredToolNames.includes(toolName)) {
throw new Error(`NapCat MCP tool registry self-check failed: ${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") { if (parseNapcatAutomationClassification("manual-review") !== "manual-review") {
throw new Error("NapCat classification parser self-check failed"); throw new Error("NapCat classification parser self-check failed");
@ -175,6 +265,24 @@ export async function runSelfTest(): Promise<void> {
"NapCat upstream audit dry-run artifact plan self-check failed", "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({ const codexCommand = buildNapcatCodexExecCommand({
artifactRoot: "/vol1/docker/kt-codex/artifacts/smoke", artifactRoot: "/vol1/docker/kt-codex/artifacts/smoke",
contextPacketPath: contextPacketPath:

View File

@ -100,10 +100,22 @@ const napcatNasCodexArtifactRoot = '/vol1/docker/kt-codex/artifacts';
const napcatLocalArtifactRoot = '.kt-workspace/test-artifacts'; const napcatLocalArtifactRoot = '.kt-workspace/test-artifacts';
const napcatAutomationSkeletonArtifactRoot = const napcatAutomationSkeletonArtifactRoot =
'.kt-workspace/test-artifacts/napcat-automation'; '.kt-workspace/test-artifacts/napcat-automation';
const defaultNapcatForkRepo = 'KTeam/NapCatQQ';
const defaultNapcatUpstreamRepo = 'NapNeko/NapCatQQ'; export const napcatAutomationDefaults = {
const defaultNapcatCandidateBranch = 'napcat-upstream-sync/candidate'; apiImageTag: 'main-<jenkins-build>',
const defaultNapcatWorkspaceRoot = '/vol1/docker/kt-codex/workspace/KT'; 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 { interface NapcatPromptSkeletonConfig {
artifactSlug: string; artifactSlug: string;
@ -189,14 +201,14 @@ export function buildNapcatSyncCandidateReview(
input: NapcatSyncCandidateReviewInput, input: NapcatSyncCandidateReviewInput,
) { ) {
const context = { const context = {
candidateBranch: input.candidateBranch ?? defaultNapcatCandidateBranch, candidateBranch: input.candidateBranch ?? napcatAutomationDefaults.candidateBranch,
forkBranch: input.forkBranch ?? 'dev', forkBranch: input.forkBranch ?? napcatAutomationDefaults.forkBranch,
forkRepo: input.forkRepo ?? defaultNapcatForkRepo, forkRepo: input.forkRepo ?? napcatAutomationDefaults.forkRepo,
lastAcceptedUpstreamBase: lastAcceptedUpstreamBase:
input.lastAcceptedUpstreamBase ?? 'LAST_ACCEPTED_UPSTREAM_BASE', input.lastAcceptedUpstreamBase ?? napcatAutomationDefaults.lastAcceptedUpstreamBase,
upstreamReleaseTag: input.upstreamReleaseTag ?? 'UPSTREAM_RELEASE_REF', upstreamReleaseTag: input.upstreamReleaseTag ?? napcatAutomationDefaults.upstreamReleaseRef,
upstreamRepo: input.upstreamRepo ?? defaultNapcatUpstreamRepo, upstreamRepo: input.upstreamRepo ?? napcatAutomationDefaults.upstreamRepo,
workspaceRoot: input.workspaceRoot ?? defaultNapcatWorkspaceRoot, workspaceRoot: input.workspaceRoot ?? napcatAutomationDefaults.workspaceRoot,
}; };
return buildNapcatPromptSkeleton({ return buildNapcatPromptSkeleton({
@ -209,13 +221,13 @@ export function buildNapcatSyncCandidateReview(
}, },
{ {
command: 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.', description: 'Inspect recent candidate commits without changing refs.',
readOnly: true, readOnly: true,
}, },
{ {
command: 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.', description: 'Summarize candidate file churn for human review.',
readOnly: true, readOnly: true,
}, },
@ -239,13 +251,14 @@ export function buildNapcatRuntimeReleaseReadiness(
input: NapcatRuntimeReleaseReadinessInput, input: NapcatRuntimeReleaseReadinessInput,
) { ) {
const context = { const context = {
apiImageTag: input.apiImageTag ?? 'main-<jenkins-build>', apiImageTag: input.apiImageTag ?? napcatAutomationDefaults.apiImageTag,
candidateBranch: input.candidateBranch ?? defaultNapcatCandidateBranch, candidateBranch: input.candidateBranch ?? napcatAutomationDefaults.candidateBranch,
forkRepo: input.forkRepo ?? defaultNapcatForkRepo, forkBranch: input.forkBranch ?? napcatAutomationDefaults.forkBranch,
napcatImageTag: input.napcatImageTag ?? 'kt-napcat-desktop-cn:<profile>', forkRepo: input.forkRepo ?? napcatAutomationDefaults.forkRepo,
profile: input.profile ?? 'desktop-cn', napcatImageTag: input.napcatImageTag ?? napcatAutomationDefaults.runtimeImageTag,
upstreamReleaseTag: input.upstreamReleaseTag ?? 'UPSTREAM_RELEASE_REF', profile: input.profile ?? napcatAutomationDefaults.runtimeProfile,
workspaceRoot: input.workspaceRoot ?? defaultNapcatWorkspaceRoot, upstreamReleaseTag: input.upstreamReleaseTag ?? napcatAutomationDefaults.upstreamReleaseRef,
workspaceRoot: input.workspaceRoot ?? napcatAutomationDefaults.workspaceRoot,
}; };
return buildNapcatPromptSkeleton({ return buildNapcatPromptSkeleton({
@ -288,11 +301,12 @@ export function buildNapcatRemoteDevHandoff(
input: NapcatRemoteDevHandoffInput, input: NapcatRemoteDevHandoffInput,
) { ) {
const context = { const context = {
candidateBranch: input.candidateBranch ?? defaultNapcatCandidateBranch, candidateBranch: input.candidateBranch ?? napcatAutomationDefaults.candidateBranch,
forkRepo: input.forkRepo ?? defaultNapcatForkRepo, forkBranch: input.forkBranch ?? napcatAutomationDefaults.forkBranch,
targetHost: input.targetHost ?? 'nas', forkRepo: input.forkRepo ?? napcatAutomationDefaults.forkRepo,
upstreamReleaseTag: input.upstreamReleaseTag ?? 'UPSTREAM_RELEASE_REF', targetHost: input.targetHost ?? napcatAutomationDefaults.targetHost,
workspaceRoot: input.workspaceRoot ?? defaultNapcatWorkspaceRoot, upstreamReleaseTag: input.upstreamReleaseTag ?? napcatAutomationDefaults.upstreamReleaseRef,
workspaceRoot: input.workspaceRoot ?? napcatAutomationDefaults.workspaceRoot,
}; };
return buildNapcatPromptSkeleton({ return buildNapcatPromptSkeleton({
@ -329,9 +343,9 @@ export function buildNasCodexBootstrapPlan(input: NasCodexBootstrapPlanInput) {
input.artifactRoot?.trim() || input.artifactRoot?.trim() ||
`${napcatAutomationSkeletonArtifactRoot}/nas-codex-bootstrap`; `${napcatAutomationSkeletonArtifactRoot}/nas-codex-bootstrap`;
const context = { const context = {
codexHome: input.codexHome ?? '/vol1/docker/kt-codex/home/.codex', codexHome: input.codexHome ?? napcatAutomationDefaults.codexHome,
serviceName: input.serviceName ?? 'kt-codex-automation', serviceName: input.serviceName ?? napcatAutomationDefaults.bootstrapServiceName,
workspaceRoot: input.workspaceRoot ?? defaultNapcatWorkspaceRoot, workspaceRoot: input.workspaceRoot ?? napcatAutomationDefaults.workspaceRoot,
}; };
const requestedExecute = input.execute === true; 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. * @returns The configured workspace root or the stabilized NAS kt-codex workspace path.
*/ */
function resolveNapcatCodexWorkspaceRoot(workspaceRoot?: string): string { 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: 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.', description: 'List upstream release files changed since the last accepted base.',
readOnly: true, readOnly: true,
}, },
{ {
command: 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.', description: 'List KT fork patch files for deterministic overlap checks.',
readOnly: true, readOnly: true,
}, },
{ {
command: 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.', description: 'Probe the dry merge shape without updating the worktree or refs.',
readOnly: true, readOnly: true,
}, },