From efc6f5019954b1a67c9dded9aeb376765876745f Mon Sep 17 00:00:00 2001 From: sunlei Date: Wed, 24 Jun 2026 23:12:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9A=E4=B9=89NapCat=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=8C=96=E5=AE=A1=E8=AE=A1=E5=A5=91=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../runtime-release-readiness.schema.json | 34 +++++++++ .../napcat/schemas/upstream-audit.schema.json | 33 +++++++++ src/selfTest.ts | 25 +++++++ src/tools/napcatAutomation.types.ts | 72 +++++++++++++++++++ 4 files changed, 164 insertions(+) create mode 100644 prompts/napcat/schemas/runtime-release-readiness.schema.json create mode 100644 prompts/napcat/schemas/upstream-audit.schema.json create mode 100644 src/tools/napcatAutomation.types.ts diff --git a/prompts/napcat/schemas/runtime-release-readiness.schema.json b/prompts/napcat/schemas/runtime-release-readiness.schema.json new file mode 100644 index 0000000..9d8bc9f --- /dev/null +++ b/prompts/napcat/schemas/runtime-release-readiness.schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "additionalProperties": false, + "required": [ + "sourceValidation", + "imageValidation", + "apiPromotionReadiness", + "onlineSmokeReadiness", + "rollbackPointer" + ], + "properties": { + "sourceValidation": { + "type": "string", + "minLength": 1 + }, + "imageValidation": { + "type": "string", + "minLength": 1 + }, + "apiPromotionReadiness": { + "type": "string", + "minLength": 1 + }, + "onlineSmokeReadiness": { + "type": "string", + "minLength": 1 + }, + "rollbackPointer": { + "type": "string", + "minLength": 1 + } + } +} diff --git a/prompts/napcat/schemas/upstream-audit.schema.json b/prompts/napcat/schemas/upstream-audit.schema.json new file mode 100644 index 0000000..883ecd3 --- /dev/null +++ b/prompts/napcat/schemas/upstream-audit.schema.json @@ -0,0 +1,33 @@ +{ + "$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 + } + } +} diff --git a/src/selfTest.ts b/src/selfTest.ts index 5178b2d..382f570 100644 --- a/src/selfTest.ts +++ b/src/selfTest.ts @@ -35,6 +35,11 @@ import { findTaskRecordGovernanceFindings, isBenignCredentialReviewValue, } from "./tools/review.js"; +import { + napcatAutomationReasonCodes, + parseNapcatAutomationClassification, + upstreamAuditOutputSchema, +} from "./tools/napcatAutomation.types.js"; import { buildBusinessTestPlan, buildNapcatDeviceProfileCheck, @@ -54,7 +59,27 @@ import { buildPushPlan, buildRemoteHealthCheck, } from "./tools/workflow.js"; +/** + * Runs ktWorkflow guardrail smoke checks from the CLI self-test entry; writes local evidence under the KT workspace and throws on any broken workflow contract. + * @returns A promise that resolves after all contract checks and evidence writing complete. + */ export async function runSelfTest(): Promise { + 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"); + } + const reviewClassifier = { localizedSecretLabelAllowed: isBenignCredentialReviewValue("密钥"), realTokenRejected: !isBenignCredentialReviewValue( diff --git a/src/tools/napcatAutomation.types.ts b/src/tools/napcatAutomation.types.ts new file mode 100644 index 0000000..77022ac --- /dev/null +++ b/src/tools/napcatAutomation.types.ts @@ -0,0 +1,72 @@ +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 string from deterministic audit metadata or Codex JSON output; must match the shared NapCat automation taxonomy. + * @returns A supported NapCat automation classification for downstream workflow decisions. + */ +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; +}