kt-template-online-api/docs/plans/2026-06-24-napcatqq-upstream-sync-runtime-release-pipeline-implementation-plan.md

35 KiB
Raw Permalink Blame History

NapCatQQ Upstream Sync Runtime Release Pipeline Implementation Plan

Execution note: Execute this plan task-by-task with the KT-local workflow and use the checkboxes to track plan state.

Goal: Build a ktWorkflow-owned automation path that audits upstream NapCatQQ releases, assists review with Codex CLI, builds verified KT NapCat runtime images, and promotes them to API through explicit deployment parameters.

Architecture: mcp/ktWorkflow owns collectors, prompts, schema validation, CLI wrappers, MCP tools, and scheduler entry points. Node/kt-template-online-api remains the runtime image and API deployment contract owner. Jenkins and NAS timers only call ktWorkflow scripts and never duplicate the audit algorithm.

Tech Stack: TypeScript ESM, MCP SDK, zod, Node child_process, Codex CLI exec, Jenkins Pipeline, Docker, K8s, NestJS API runtime config, Jest.


File Structure

D:\MyFiles\KT\mcp\ktWorkflow

  • Create prompts/napcat/upstream-audit.md: Codex CLI prompt for upstream release risk classification.
  • Create prompts/napcat/sync-candidate-review.md: Codex CLI prompt for candidate branch review.
  • Create prompts/napcat/runtime-release-readiness.md: Codex CLI prompt for image promotion readiness.
  • Create prompts/napcat/remote-dev-handoff.md: Codex CLI prompt for NAS remote-development handoff.
  • Create prompts/napcat/schemas/upstream-audit.schema.json: JSON Schema used by codex exec --output-schema.
  • Create prompts/napcat/schemas/runtime-release-readiness.schema.json: JSON Schema for release readiness reports.
  • Create src/tools/napcatAutomation.types.ts: zod schemas, normalized input types, artifact result types, and constants.
  • Create src/tools/napcatAutomation.prompts.ts: prompt path resolution and prompt loading helpers.
  • Create src/tools/napcatAutomation.ts: deterministic collectors, Codex runner, artifact writer, and public builders for tools/scripts.
  • Modify src/types.ts: exported MCP input/result interfaces.
  • Modify src/core/cli.ts: CLI parsers for NapCat automation scripts.
  • Modify src/registerTools.ts: MCP tool registration.
  • Modify src/server.ts: CLI flag dispatch.
  • Modify src/core/constants.ts: registeredToolNames.
  • Modify src/selfTest.ts: deterministic self-tests for CLI parser, audit classification, prompt/schema presence, and safe command generation.
  • Modify package.json: scripts napcat-upstream-audit, napcat-sync-candidate-review, napcat-runtime-release-readiness, and nas-codex-bootstrap.
  • Modify README.md: public ktWorkflow usage docs and NAS command examples.

D:\MyFiles\KT\Node\kt-template-online-api

  • Modify scripts/napcat-desktop-cn-stage-build.mjs: include upstream release tag/commit, base image digest, Jenkins build URL, and fork artifact metadata.
  • Modify test/modules/qqbot/napcat/napcat-desktop-cn-image.spec.ts: assert richer marker and API deployment override contract.
  • Create test/modules/qqbot/napcat/napcat-runtime-promotion.spec.ts: static tests for Jenkins/K8s runtime image/profile override behavior.
  • Modify Jenkinsfile: add optional QQBOT_NAPCAT_IMAGE_OVERRIDE and QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE parameters and set K8s env during deploy.
  • Modify k8s/prod/api.yaml: keep safe defaults while allowing Jenkins kubectl set env override.
  • Modify README.md and API.md: document runtime promotion and rollback contract.

D:\MyFiles\KT\GitHub\NapCatQQ

  • Create ci/kt-runtime-release.md: repo-local release checklist used by Jenkins and human operators.
  • No source login behavior changes are part of this plan. If upstream sync reveals login conflicts, create a separate NapCatQQ implementation plan.

D:\MyFiles\KT

  • Modify TASKS.md: record the completed planning state and verification evidence.

Task 1: ktWorkflow NapCat Automation Contracts

Files:

  • Create: D:\MyFiles\KT\mcp\ktWorkflow\src\tools\napcatAutomation.types.ts

  • Create: D:\MyFiles\KT\mcp\ktWorkflow\prompts\napcat\schemas\upstream-audit.schema.json

  • Create: D:\MyFiles\KT\mcp\ktWorkflow\prompts\napcat\schemas\runtime-release-readiness.schema.json

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\selfTest.ts

  • Step 1: Write the failing self-test

Add a self-test block that imports the new schemas and verifies reason-code normalization.

import {
  napcatAutomationReasonCodes,
  parseNapcatAutomationClassification,
  upstreamAuditOutputSchema,
} from './tools/napcatAutomation.types.js';

const napcatAuditSchemaSmoke = upstreamAuditOutputSchema.safeParse({
  classification: 'manual-review',
  reasonCodes: ['HOT_ZONE_CHANGED'],
  recommendedAction: 'request-human-review',
  summary: 'Login hot-zone changed.',
});
if (!napcatAuditSchemaSmoke.success) {
  throw new Error('NapCat upstream audit schema self-check failed');
}
if (!napcatAutomationReasonCodes.includes('HOT_ZONE_CHANGED')) {
  throw new Error('NapCat reason-code list self-check failed');
}
if (parseNapcatAutomationClassification('manual-review') !== 'manual-review') {
  throw new Error('NapCat classification parser self-check failed');
}
  • Step 2: Run the self-test and confirm RED

Run:

pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run self-test

Expected: fails because napcatAutomation.types.js does not exist.

  • Step 3: Add zod types and constants

Create src/tools/napcatAutomation.types.ts:

import { z } from 'zod';

export const napcatAutomationClassifications = [
  'safe-candidate',
  'manual-review',
  'blocked',
] as const;

export const napcatAutomationReasonCodes = [
  'NO_UPSTREAM_CHANGE',
  'HOT_ZONE_CHANGED',
  'FORK_PATCH_OVERLAP',
  'DRY_MERGE_CONFLICT',
  'BUILD_GRAPH_CHANGED',
  'METADATA_UNAVAILABLE',
  'CODEX_SCHEMA_INVALID',
] as const;

export const upstreamAuditOutputSchema = z.object({
  classification: z.enum(napcatAutomationClassifications),
  reasonCodes: z.array(z.enum(napcatAutomationReasonCodes)).min(1),
  recommendedAction: z.enum([
    'no-op',
    'create-candidate-branch',
    'request-human-review',
    'block',
  ]),
  summary: z.string().min(1),
});

export type NapcatAutomationClassification =
  (typeof napcatAutomationClassifications)[number];

export interface NapcatUpstreamAuditInput {
  artifactRoot?: string;
  createCandidateBranch?: boolean;
  execute?: boolean;
  forkBranch?: string;
  forkRepo?: string;
  lastAcceptedUpstreamBase?: string;
  upstreamReleaseTag?: string;
  upstreamRepo?: string;
  useCodex?: boolean;
}

export interface NapcatAutomationArtifact {
  path: string;
  type: 'context' | 'json' | 'jsonl' | 'markdown' | 'script';
}

export interface NapcatAutomationResult {
  artifacts: NapcatAutomationArtifact[];
  classification: NapcatAutomationClassification;
  execute: boolean;
  recommendedAction: string;
  summary: string;
}

/**
 * Parses the upstream audit classification emitted by deterministic collectors or Codex.
 * @param value - Raw classification value from JSON output.
 * @returns A supported classification value.
 */
export function parseNapcatAutomationClassification(
  value: string,
): NapcatAutomationClassification {
  const parsed = z.enum(napcatAutomationClassifications).safeParse(value);
  if (!parsed.success) {
    throw new Error(`Unsupported NapCat audit classification: ${value}`);
  }
  return parsed.data;
}
  • Step 4: Add JSON schemas for Codex CLI

Create prompts/napcat/schemas/upstream-audit.schema.json:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "additionalProperties": false,
  "required": ["classification", "reasonCodes", "recommendedAction", "summary"],
  "properties": {
    "classification": {
      "enum": ["safe-candidate", "manual-review", "blocked"]
    },
    "reasonCodes": {
      "type": "array",
      "minItems": 1,
      "items": {
        "enum": [
          "NO_UPSTREAM_CHANGE",
          "HOT_ZONE_CHANGED",
          "FORK_PATCH_OVERLAP",
          "DRY_MERGE_CONFLICT",
          "BUILD_GRAPH_CHANGED",
          "METADATA_UNAVAILABLE",
          "CODEX_SCHEMA_INVALID"
        ]
      }
    },
    "recommendedAction": {
      "enum": ["no-op", "create-candidate-branch", "request-human-review", "block"]
    },
    "summary": {
      "type": "string",
      "minLength": 1
    }
  }
}

Create prompts/napcat/schemas/runtime-release-readiness.schema.json with sourceValidation, imageValidation, apiPromotionReadiness, onlineSmokeReadiness, and rollbackPointer string fields.

  • Step 5: Run GREEN

Run:

pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run self-test
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run typecheck

Expected: both pass.

  • Step 6: Commit
git -C D:\MyFiles\KT\mcp\ktWorkflow add prompts/napcat src/tools/napcatAutomation.types.ts src/selfTest.ts
git -C D:\MyFiles\KT\mcp\ktWorkflow commit -m "feat: 定义NapCat自动化审计契约"

Task 2: ktWorkflow Prompt Pack and Safe Prompt Loader

Files:

  • Create: D:\MyFiles\KT\mcp\ktWorkflow\prompts\napcat\upstream-audit.md

  • Create: D:\MyFiles\KT\mcp\ktWorkflow\prompts\napcat\sync-candidate-review.md

  • Create: D:\MyFiles\KT\mcp\ktWorkflow\prompts\napcat\runtime-release-readiness.md

  • Create: D:\MyFiles\KT\mcp\ktWorkflow\prompts\napcat\remote-dev-handoff.md

  • Create: D:\MyFiles\KT\mcp\ktWorkflow\src\tools\napcatAutomation.prompts.ts

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\selfTest.ts

  • Step 1: Write the failing self-test

import {
  loadNapcatAutomationPrompt,
  napcatAutomationPromptNames,
} from './tools/napcatAutomation.prompts.js';

for (const promptName of napcatAutomationPromptNames) {
  const promptText = loadNapcatAutomationPrompt(promptName);
  if (!promptText.includes('Do not edit files')) {
    throw new Error(`NapCat prompt safety contract missing: ${promptName}`);
  }
}
  • Step 2: Run RED
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run self-test

Expected: fails because prompt loader does not exist.

  • Step 3: Create prompt loader
import { readFileSync } from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

export const napcatAutomationPromptNames = [
  'upstream-audit',
  'sync-candidate-review',
  'runtime-release-readiness',
  'remote-dev-handoff',
] as const;

export type NapcatAutomationPromptName =
  (typeof napcatAutomationPromptNames)[number];

const promptsRoot = path.resolve(
  fileURLToPath(new URL('../../..', import.meta.url)),
  'prompts',
  'napcat',
);

/**
 * Loads a source-controlled NapCat automation prompt by stable prompt name.
 * @param name - Prompt identifier that maps to `prompts/napcat/${name}.md`.
 * @returns UTF-8 prompt text used by Codex CLI automation.
 */
export function loadNapcatAutomationPrompt(
  name: NapcatAutomationPromptName,
): string {
  return readFileSync(path.join(promptsRoot, `${name}.md`), 'utf8');
}
  • Step 4: Create prompts

Each prompt must include these exact safety lines:

Do not edit files.
Do not run merge, commit, push, deploy, or Docker mutation commands.
Use only the supplied context packet.
Return JSON that matches the requested schema.

upstream-audit.md must also include the three classifications and the seven reason codes from Task 1.

  • Step 5: Run GREEN
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run self-test
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run typecheck

Expected: both pass.

  • Step 6: Commit
git -C D:\MyFiles\KT\mcp\ktWorkflow add prompts/napcat src/tools/napcatAutomation.prompts.ts src/selfTest.ts
git -C D:\MyFiles\KT\mcp\ktWorkflow commit -m "feat: 增加NapCat自动化提示词包"

Task 3: Deterministic Upstream Audit Collector

Files:

  • Create: D:\MyFiles\KT\mcp\ktWorkflow\src\tools\napcatAutomation.ts

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\tools\napcatAutomation.types.ts

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\selfTest.ts

  • Step 1: Write RED self-test for hot-zone classification

import { classifyNapcatUpstreamAudit } from './tools/napcatAutomation.js';

const hotZoneAudit = classifyNapcatUpstreamAudit({
  dryMergeConflict: false,
  forkPatchFiles: ['packages/napcat-core/login/runtime.ts'],
  upstreamChangedFiles: ['packages/napcat-core/login/runtime.ts'],
});
if (hotZoneAudit.classification !== 'manual-review') {
  throw new Error('NapCat hot-zone audit classification self-check failed');
}
if (!hotZoneAudit.reasonCodes.includes('HOT_ZONE_CHANGED')) {
  throw new Error('NapCat hot-zone reason-code self-check failed');
}
  • Step 2: Run RED
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run self-test

Expected: fails because classifyNapcatUpstreamAudit does not exist.

  • Step 3: Implement classifier and context packet builder

Add this public classifier:

const hotZonePatterns = [
  /^packages\/napcat-core\/.*login/i,
  /^packages\/napcat-core\/.*qrcode/i,
  /^packages\/napcat-shell\//i,
  /^packages\/napcat-framework\//i,
  /^packages\/napcat-webui-backend\/.*QQLogin/i,
  /^packages\/napcat-webui-backend\/.*Data/i,
  /^packages\/napcat-webui-backend\/.*auth/i,
  /^packages\/napcat-webui-frontend\//i,
  /^packages\/napcat-adapter\//i,
  /^packages\/napcat-onebot\//i,
  /^packages\/napcat-vite\//i,
  /^package\.json$/i,
  /^pnpm-lock\.yaml$/i,
  /^tsconfig.*\.json$/i,
  /^vite.*\.ts$/i,
];

export interface NapcatAuditClassificationInput {
  dryMergeConflict: boolean;
  forkPatchFiles: string[];
  upstreamChangedFiles: string[];
}

/**
 * Classifies upstream release risk from already-collected file-level facts.
 * @param input - Changed files, fork patch files, and dry-merge conflict status.
 * @returns Schema-compatible classification used before optional Codex review.
 */
export function classifyNapcatUpstreamAudit(
  input: NapcatAuditClassificationInput,
): {
  classification: NapcatAutomationClassification;
  reasonCodes: string[];
  recommendedAction: string;
  summary: string;
} {
  const upstream = new Set(input.upstreamChangedFiles);
  const overlapFiles = input.forkPatchFiles.filter((file) => upstream.has(file));
  const hotZoneFiles = input.upstreamChangedFiles.filter((file) =>
    hotZonePatterns.some((pattern) => pattern.test(file)),
  );
  if (input.dryMergeConflict) {
    return {
      classification: 'blocked',
      reasonCodes: ['DRY_MERGE_CONFLICT'],
      recommendedAction: 'block',
      summary: 'Dry merge reported conflicts.',
    };
  }
  if (hotZoneFiles.length > 0 || overlapFiles.length > 0) {
    return {
      classification: 'manual-review',
      reasonCodes: [
        ...(hotZoneFiles.length > 0 ? ['HOT_ZONE_CHANGED'] : []),
        ...(overlapFiles.length > 0 ? ['FORK_PATCH_OVERLAP'] : []),
      ],
      recommendedAction: 'request-human-review',
      summary: 'Upstream changes require manual review before sync.',
    };
  }
  return {
    classification: 'safe-candidate',
    reasonCodes: ['NO_UPSTREAM_CHANGE'],
    recommendedAction: 'create-candidate-branch',
    summary: 'No hot-zone or fork patch overlap was detected.',
  };
}
  • Step 4: Add command builders without executing mutations

Implement buildNapcatUpstreamAudit(input) so execute=false returns a script containing only bounded read-only commands:

git fetch upstream --tags --prune
git fetch origin --prune
git diff --name-only "$LAST_ACCEPTED_UPSTREAM_BASE..$UPSTREAM_RELEASE_COMMIT"
git merge-tree "$FORK_BRANCH" "$UPSTREAM_RELEASE_COMMIT"

Do not include git merge, git push, docker build, or kubectl.

  • Step 5: Run GREEN
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run self-test
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run typecheck

Expected: both pass.

  • Step 6: Commit
git -C D:\MyFiles\KT\mcp\ktWorkflow add src/tools/napcatAutomation.ts src/tools/napcatAutomation.types.ts src/selfTest.ts
git -C D:\MyFiles\KT\mcp\ktWorkflow commit -m "feat: 增加NapCat上游审计采集器"

Task 4: Codex CLI Runner and Artifact Capture

Files:

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\tools\napcatAutomation.ts

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\selfTest.ts

  • Step 1: Write RED self-test for safe Codex command

import { buildNapcatCodexExecCommand } from './tools/napcatAutomation.js';

const codexCommand = buildNapcatCodexExecCommand({
  artifactRoot: '/vol1/docker/kt-codex/artifacts/smoke',
  contextPacketPath: '/vol1/docker/kt-codex/artifacts/smoke/context-packet.md',
  outputSchemaPath: '/vol1/docker/kt-codex/workspace/KT/mcp/ktWorkflow/prompts/napcat/schemas/upstream-audit.schema.json',
  promptName: 'upstream-audit',
  workspaceRoot: '/vol1/docker/kt-codex/workspace/KT',
});
if (!codexCommand.includes('--ask-for-approval never')) {
  throw new Error('NapCat Codex runner approval policy self-check failed');
}
if (codexCommand.includes('git push') || codexCommand.includes('kubectl')) {
  throw new Error('NapCat Codex runner mutation guard self-check failed');
}
  • Step 2: Run RED
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run self-test

Expected: fails because buildNapcatCodexExecCommand does not exist.

  • Step 3: Implement command builder

The command builder must shell-quote every path and include:

CODEX_HOME=/vol1/docker/kt-codex/home/.codex
codex exec
--cd /vol1/docker/kt-codex/workspace/KT
--profile automation
--sandbox workspace-write
--ask-for-approval never
--json
--ephemeral
--output-schema /vol1/docker/kt-codex/workspace/KT/mcp/ktWorkflow/prompts/napcat/schemas/upstream-audit.schema.json
--output-last-message /vol1/docker/kt-codex/artifacts/smoke/codex-upstream-audit.md
  • Step 4: Implement execution mode

When execute=true and useCodex=true, buildNapcatUpstreamAudit must:

  1. Write a context packet under the artifact root.
  2. Run Codex CLI with a timeout of 10 minutes.
  3. Capture JSONL stdout to codex-upstream-audit.jsonl.
  4. Parse the final JSON payload with upstreamAuditOutputSchema.
  5. Return classification='blocked' with CODEX_SCHEMA_INVALID if parsing fails.
  • Step 5: Run GREEN
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run self-test
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run typecheck

Expected: both pass.

  • Step 6: Commit
git -C D:\MyFiles\KT\mcp\ktWorkflow add src/tools/napcatAutomation.ts src/selfTest.ts
git -C D:\MyFiles\KT\mcp\ktWorkflow commit -m "feat: 封装NapCat Codex审计执行器"

Task 5: MCP Tools and CLI Scripts

Files:

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\types.ts

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\core\cli.ts

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\registerTools.ts

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\server.ts

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\core\constants.ts

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\package.json

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\README.md

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\selfTest.ts

  • Step 1: Write RED self-test for tool registration and CLI parser

import { parseNapcatUpstreamAuditCliArgs } from './core/cli.js';
import { registeredToolNames } from './core/constants.js';

const napcatCli = parseNapcatUpstreamAuditCliArgs([
  'node',
  'server',
  '--napcat-upstream-audit',
  '--execute',
  '--use-codex',
  '--artifact-root',
  '/vol1/docker/kt-codex/artifacts/napcat-upstream-sync',
]);
if (!napcatCli.execute || !napcatCli.useCodex) {
  throw new Error('NapCat upstream audit CLI parser self-check failed');
}
if (!registeredToolNames.includes('kt_napcat_upstream_audit')) {
  throw new Error('NapCat MCP tool registry self-check failed');
}
  • Step 2: Run RED
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run self-test

Expected: fails because parser and tool names do not exist.

  • Step 3: Register MCP tools

Add tools:

server.registerTool(
  'kt_napcat_upstream_audit',
  {
    description: 'Generate or execute a NapCatQQ upstream release audit through ktWorkflow.',
    inputSchema: {
      artifactRoot: z.string().optional(),
      createCandidateBranch: z.boolean().default(false),
      execute: z.boolean().default(false),
      forkBranch: z.string().default('kt/runtime-maintenance'),
      forkRepo: z.string().default('D:/MyFiles/KT/GitHub/NapCatQQ'),
      lastAcceptedUpstreamBase: z.string().optional(),
      upstreamReleaseTag: z.string().optional(),
      upstreamRepo: z.string().default('NapNeko/NapCatQQ'),
      useCodex: z.boolean().default(false),
    },
    title: 'KT NapCat Upstream Audit',
  },
  async (input) => response(await buildNapcatUpstreamAudit(input)),
);

Also register kt_napcat_sync_candidate_review, kt_napcat_runtime_release_readiness, kt_napcat_remote_dev_handoff, and kt_nas_codex_bootstrap_plan.

  • Step 4: Add CLI flags and package scripts

package.json scripts:

{
  "napcat-upstream-audit": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-upstream-audit",
  "napcat-sync-candidate-review": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-sync-candidate-review",
  "napcat-runtime-release-readiness": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --napcat-runtime-release-readiness",
  "nas-codex-bootstrap": "node --import ./node_modules/tsx/dist/loader.mjs src/server.ts --nas-codex-bootstrap"
}
  • Step 5: Run GREEN
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run napcat-upstream-audit -- --artifact-root .kt-workspace/test-artifacts/napcat-upstream-sync
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run self-test
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run typecheck

Expected: dry-run prints commands/artifacts, self-test/typecheck pass.

  • Step 6: Commit
git -C D:\MyFiles\KT\mcp\ktWorkflow add package.json README.md src
git -C D:\MyFiles\KT\mcp\ktWorkflow commit -m "feat: 接入NapCat自动化MCP工具和CLI"

Task 6: NAS Codex Bootstrap Plan Tool

Files:

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\tools\napcatAutomation.ts

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\src\selfTest.ts

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\README.md

  • Step 1: Write RED self-test for Linux-only bootstrap commands

import { buildNasCodexBootstrapPlan } from './tools/napcatAutomation.js';

const bootstrap = buildNasCodexBootstrapPlan({ execute: false });
const commandText = bootstrap.commands.map((item) => item.command).join('\n');
if (!commandText.includes('/vol1/docker/kt-codex/home/.codex')) {
  throw new Error('NAS Codex bootstrap CODEX_HOME self-check failed');
}
if (commandText.includes('C:\\Users')) {
  throw new Error('NAS Codex bootstrap Windows path guard self-check failed');
}
  • Step 2: Run RED
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run self-test

Expected: fails because bootstrap builder does not exist.

  • Step 3: Implement dry-run bootstrap

The dry-run must emit a bounded SSH here-string command that checks:

node --version
corepack --version
pnpm --version
git --version
docker --version
codex --version
test -d /vol1/docker/kt-codex/workspace/KT
test -d /vol1/docker/kt-codex/home/.codex

It must not copy secrets in dry-run mode.

  • Step 4: Add execute mode with explicit safe operations

execute=true may create directories and install packages, but must not push, merge, deploy, or edit business repos.

  • Step 5: Run GREEN
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run nas-codex-bootstrap -- --dry-run
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run self-test
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run typecheck

Expected: dry-run prints NAS setup checks, self-test/typecheck pass.

  • Step 6: Commit
git -C D:\MyFiles\KT\mcp\ktWorkflow add README.md src
git -C D:\MyFiles\KT\mcp\ktWorkflow commit -m "feat: 增加NAS Codex环境引导工具"

Task 7: API Runtime Artifact Metadata

Files:

  • Modify: D:\MyFiles\KT\Node\kt-template-online-api\scripts\napcat-desktop-cn-stage-build.mjs

  • Modify: D:\MyFiles\KT\Node\kt-template-online-api\test\modules\qqbot\napcat\napcat-desktop-cn-image.spec.ts

  • Modify: D:\MyFiles\KT\Node\kt-template-online-api\README.md

  • Modify: D:\MyFiles\KT\Node\kt-template-online-api\API.md

  • Step 1: Write RED test for richer fork artifact marker

Add assertions:

expect(script).toContain('upstreamReleaseTag');
expect(script).toContain('upstreamReleaseCommit');
expect(script).toContain('napcatBaseImageDigest');
expect(script).toContain('jenkinsBuildUrl');
  • Step 2: Run RED
corepack pnpm --dir D:\MyFiles\KT\Node\kt-template-online-api exec jest test/modules/qqbot/napcat/napcat-desktop-cn-image.spec.ts --runTestsByPath --runInBand

Expected: fails because the stage-build script only writes the older marker fields.

  • Step 3: Extend CLI args and marker

Add readArg calls and marker fields:

const upstreamReleaseTag = readArg('upstream-release-tag', 'unknown');
const upstreamReleaseCommit = readArg('upstream-release-commit', upstreamBaseCommit);
const napcatBaseImageDigest = readArg('napcat-base-image-digest', '');
const jenkinsBuildUrl = readArg('jenkins-build-url', '');

const marker = {
  builtAt: new Date().toISOString(),
  distSha256: sha256Directory(shellDist),
  forkCommit: gitCommit(napcatRoot),
  jenkinsBuildUrl,
  napcatBaseImageDigest,
  napcatMjsSha256: sha256File(napcatMjs),
  upstreamBaseCommit,
  upstreamReleaseCommit,
  upstreamReleaseTag,
};
  • Step 4: Document command shape

Add docs showing:

node scripts/napcat-desktop-cn-stage-build.mjs `
  --napcat-root D:\MyFiles\KT\GitHub\NapCatQQ `
  --upstream-release-tag v4.8.0 `
  --upstream-release-commit 0000000000000000000000000000000000000000 `
  --napcat-base-image-digest mlikiowa/napcat-docker@sha256:0000000000000000000000000000000000000000000000000000000000000000 `
  --jenkins-build-url https://jenkins.kwitsukasa.top/job/KT-NapCatQQ-Runtime-Release/1/
  • Step 5: Run GREEN
corepack pnpm --dir D:\MyFiles\KT\Node\kt-template-online-api exec jest test/modules/qqbot/napcat/napcat-desktop-cn-image.spec.ts --runTestsByPath --runInBand
corepack pnpm --dir D:\MyFiles\KT\Node\kt-template-online-api run typecheck
git -C D:\MyFiles\KT\Node\kt-template-online-api diff --check

Expected: tests/typecheck pass and diff has no whitespace errors.

  • Step 6: Commit
git -C D:\MyFiles\KT\Node\kt-template-online-api add scripts/napcat-desktop-cn-stage-build.mjs test/modules/qqbot/napcat/napcat-desktop-cn-image.spec.ts README.md API.md
git -C D:\MyFiles\KT\Node\kt-template-online-api commit -m "feat: 扩展NapCat运行时构建元数据"

Task 8: API Jenkins Runtime Promotion Override

Files:

  • Create: D:\MyFiles\KT\Node\kt-template-online-api\test\modules\qqbot\napcat\napcat-runtime-promotion.spec.ts

  • Modify: D:\MyFiles\KT\Node\kt-template-online-api\Jenkinsfile

  • Modify: D:\MyFiles\KT\Node\kt-template-online-api\k8s\prod\api.yaml

  • Modify: D:\MyFiles\KT\Node\kt-template-online-api\README.md

  • Modify: D:\MyFiles\KT\Node\kt-template-online-api\API.md

  • Step 1: Write RED static test

import { readFileSync } from 'fs';
import { join } from 'path';

const repoRoot = join(__dirname, '../../../..');
const readSource = (relativePath: string) =>
  readFileSync(join(repoRoot, relativePath), 'utf8');

describe('NapCat runtime promotion contract', () => {
  it('exposes Jenkins parameters for runtime image and profile overrides', () => {
    const jenkinsfile = readSource('Jenkinsfile');
    expect(jenkinsfile).toContain("string(name: 'QQBOT_NAPCAT_IMAGE_OVERRIDE'");
    expect(jenkinsfile).toContain("string(name: 'QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE'");
    expect(jenkinsfile).toContain('kubectl ${kubeConfigArg} ${namespaceArg} set env');
    expect(jenkinsfile).toContain('QQBOT_NAPCAT_IMAGE=${napcatImageOverride}');
    expect(jenkinsfile).toContain('QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION=${napcatProfileOverride}');
  });

  it('keeps a safe default runtime profile in the K8s manifest', () => {
    const manifest = readSource('k8s/prod/api.yaml');
    expect(manifest).toContain('value: kt-napcat-desktop-cn:desktop-cn-v10');
    expect(manifest).toContain('value: desktop-cn-v10');
  });
});
  • Step 2: Run RED
corepack pnpm --dir D:\MyFiles\KT\Node\kt-template-online-api exec jest test/modules/qqbot/napcat/napcat-runtime-promotion.spec.ts --runTestsByPath --runInBand

Expected: fails because Jenkins parameters do not exist.

  • Step 3: Add Jenkins parameters

Add:

string(name: 'QQBOT_NAPCAT_IMAGE_OVERRIDE', defaultValue: '', description: 'Verified NapCat runtime image to inject into API deployment; empty keeps manifest/default env')
string(name: 'QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE', defaultValue: '', description: 'Verified NapCat runtime profile version to inject into API deployment; empty keeps manifest/default env')
  • Step 4: Set K8s env only when override is present

Inside K8s Deploy, after set image, add:

def napcatImageOverride = params.QQBOT_NAPCAT_IMAGE_OVERRIDE?.trim()
def napcatProfileOverride = params.QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION_OVERRIDE?.trim()
if (napcatImageOverride) {
  runCmd("kubectl ${kubeConfigArg} ${namespaceArg} set env ${shellQuote("deployment/${deploymentName}")} ${shellQuote("QQBOT_NAPCAT_IMAGE=${napcatImageOverride}")}")
}
if (napcatProfileOverride) {
  runCmd("kubectl ${kubeConfigArg} ${namespaceArg} set env ${shellQuote("deployment/${deploymentName}")} ${shellQuote("QQBOT_NAPCAT_DESKTOP_PROFILE_VERSION=${napcatProfileOverride}")}")
}
  • Step 5: Run GREEN
corepack pnpm --dir D:\MyFiles\KT\Node\kt-template-online-api exec jest test/modules/qqbot/napcat/napcat-runtime-promotion.spec.ts test/modules/qqbot/napcat/napcat-desktop-cn-image.spec.ts --runTestsByPath --runInBand
corepack pnpm --dir D:\MyFiles\KT\Node\kt-template-online-api run typecheck
git -C D:\MyFiles\KT\Node\kt-template-online-api diff --check

Expected: tests/typecheck pass and diff has no whitespace errors.

  • Step 6: Commit
git -C D:\MyFiles\KT\Node\kt-template-online-api add Jenkinsfile k8s/prod/api.yaml README.md API.md test/modules/qqbot/napcat/napcat-runtime-promotion.spec.ts
git -C D:\MyFiles\KT\Node\kt-template-online-api commit -m "feat: 支持NapCat运行时镜像参数推广"

Task 9: NapCatQQ Release Checklist and Jenkins Entry Templates

Files:

  • Create: D:\MyFiles\KT\GitHub\NapCatQQ\ci\kt-runtime-release.md

  • Create: D:\MyFiles\KT\mcp\ktWorkflow\ci\jenkins\KT-NapCatQQ-Upstream-Sync.Jenkinsfile

  • Create: D:\MyFiles\KT\mcp\ktWorkflow\ci\jenkins\KT-NapCatQQ-Runtime-Release.Jenkinsfile

  • Modify: D:\MyFiles\KT\mcp\ktWorkflow\README.md

  • Step 1: Create release checklist

The checklist must include:

# KT NapCat Runtime Release Checklist

- Verify `origin` points to the KT writable fork or mirror.
- Verify `upstream` points to `https://github.com/NapNeko/NapCatQQ.git`.
- Run `pnpm install --frozen-lockfile`.
- Run focused login/runtime tests.
- Run `pnpm run typecheck`.
- Run `pnpm run build:webui`, `pnpm run build:shell`, and `pnpm run build:framework`.
- Build Docker runtime only through ktWorkflow/Jenkins.
- Do not merge upstream release branches without human review.
  • Step 2: Add upstream sync Jenkins template

The upstream sync Jenkinsfile must call only:

sh '''
  set -e
  pnpm --dir /vol1/docker/kt-codex/workspace/KT/mcp/ktWorkflow run napcat-upstream-audit -- \
    --execute \
    --use-codex \
    --artifact-root /vol1/docker/kt-codex/artifacts/napcat-upstream-sync
'''
  • Step 3: Add runtime release Jenkins template

The runtime release Jenkinsfile must call ktWorkflow readiness and API promotion commands, and must not inline the audit algorithm.

  • Step 4: Verify templates

Run:

rg -n "napcat-upstream-audit|napcat-runtime-release-readiness|git merge|git push" D:\MyFiles\KT\mcp\ktWorkflow\ci\jenkins
git -C D:\MyFiles\KT\mcp\ktWorkflow diff --check
git -C D:\MyFiles\KT\GitHub\NapCatQQ diff --check

Expected: templates contain ktWorkflow calls and do not contain automatic git merge or git push.

  • Step 5: Commit
git -C D:\MyFiles\KT\mcp\ktWorkflow add README.md ci/jenkins
git -C D:\MyFiles\KT\mcp\ktWorkflow commit -m "docs: 增加NapCatQQ自动化Jenkins入口"
git -C D:\MyFiles\KT\GitHub\NapCatQQ add ci/kt-runtime-release.md
git -C D:\MyFiles\KT\GitHub\NapCatQQ commit -m "docs: 增加KT运行时发布清单"

Task 10: Local Verification, Review, and Planning Closeout

Files:

  • Modify: D:\MyFiles\KT\TASKS.md

  • Step 1: Run local verification

pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run napcat-upstream-audit -- --artifact-root .kt-workspace/test-artifacts/napcat-upstream-sync
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run nas-codex-bootstrap -- --dry-run
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run self-test
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run typecheck
corepack pnpm --dir D:\MyFiles\KT\Node\kt-template-online-api exec jest test/modules/qqbot/napcat/napcat-desktop-cn-image.spec.ts test/modules/qqbot/napcat/napcat-runtime-promotion.spec.ts --runTestsByPath --runInBand
corepack pnpm --dir D:\MyFiles\KT\Node\kt-template-online-api run typecheck
git -C D:\MyFiles\KT\mcp\ktWorkflow diff --check
git -C D:\MyFiles\KT\Node\kt-template-online-api diff --check
git -C D:\MyFiles\KT\GitHub\NapCatQQ diff --check

Expected: all commands pass.

  • Step 2: Run KT global review
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run global-review -- --content-scan-mode changed --max-findings-per-project 20

Expected: findings=[] or only documented false positives fixed in ktWorkflow review rules.

  • Step 3: Update TASKS

Record scope, keywords, and verification evidence for:

### 2026-06-24NapCatQQ 上游同步与运行时发布流水线实施

- 范围mcp/ktWorkflow、Node/kt-template-online-api、GitHub/NapCatQQ。
- 关键词ktWorkflow NapCat 自动化、Codex CLI exec、上游 release 审计、NAS bootstrap、API runtime image/profile override。
- 验证self-test/typecheck/Jest/global-review/diff-check 通过;线上 Jenkins/NAS dry-run 等待下一阶段。
  • Step 4: Run cleanup preview
pnpm --dir D:\MyFiles\KT\mcp\ktWorkflow run cleanup-history -- --dry-run

Expected: report is reviewed. If it lists stale generated artifacts, run --execute and then rerun dry-run until deleted=[].

  • Step 5: Commit remaining docs
git -C D:\MyFiles\KT add TASKS.md
git -C D:\MyFiles\KT commit -m "docs: 记录NapCatQQ自动化实施结果"

Execution Handoff

Plan complete and saved to docs/plans/2026-06-24-napcatqq-upstream-sync-runtime-release-pipeline-implementation-plan.md.

Two execution options:

  1. Subagent-Driven (recommended) - Dispatch a fresh subagent per task, review between tasks, and keep ktWorkflow/API/NapCatQQ commits independent.
  2. Inline Execution - Execute tasks in this session using KT local execution, with review checkpoints after each repository boundary.

Recommended choice: 1. This work touches three repositories and two runtime environments, so task-level subagents plus parent review will keep scope cleaner.