ktworkflow-mcp/src/tools/napcatAutomation.prompts.ts

65 lines
2.3 KiB
TypeScript

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',
);
const promptsRootBoundary = promptsRoot.endsWith(path.sep)
? promptsRoot
: `${promptsRoot}${path.sep}`;
const napcatAutomationPromptNameSet = new Set<string>(
napcatAutomationPromptNames,
);
const napcatAutomationPromptFileNames = {
'upstream-audit': 'upstream-audit.md',
'sync-candidate-review': 'sync-candidate-review.md',
'runtime-release-readiness': 'runtime-release-readiness.md',
'remote-dev-handoff': 'remote-dev-handoff.md',
} satisfies Record<NapcatAutomationPromptName, string>;
/**
* Parses an external prompt name into the source-controlled NapCat prompt enum.
* @param value - Raw prompt name from CLI, JSON, MCP input, or a typed caller; only exact entries in `napcatAutomationPromptNames` are accepted.
* @returns A stable prompt name that can be mapped to a fixed file under `prompts/napcat`.
*/
export function parseNapcatAutomationPromptName(
value: string,
): NapcatAutomationPromptName {
if (napcatAutomationPromptNameSet.has(value)) {
return value as NapcatAutomationPromptName;
}
throw new Error(`Unsupported NapCat automation prompt: ${value}`);
}
/**
* Loads a source-controlled NapCat automation prompt by stable prompt name.
* @param name - Prompt identifier from `napcatAutomationPromptNames`; runtime callers may still pass untyped external strings, so the loader re-validates and resolves only fixed filenames.
* @returns UTF-8 prompt text used by Codex CLI automation.
*/
export function loadNapcatAutomationPrompt(
name: NapcatAutomationPromptName,
): string {
const promptName = parseNapcatAutomationPromptName(String(name));
const promptPath = path.resolve(
promptsRoot,
napcatAutomationPromptFileNames[promptName],
);
if (!promptPath.startsWith(promptsRootBoundary)) {
throw new Error(`NapCat automation prompt escaped prompt root: ${name}`);
}
return readFileSync(promptPath, 'utf8');
}