description 前綴、沒有 frontmatter、不出現平台專屬字樣——這三件事每一份流程 正本都要驗,第二份正本出現時就該抽出來,而不是再抄一次。順帶把讀正本、讀規則 正本、讀模板三個路徑組合也收在同一處。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
63 lines
2.0 KiB
JavaScript
63 lines
2.0 KiB
JavaScript
/**
|
|
* 流程正本與規則正本的共用檢查。
|
|
*
|
|
* 這些檔案是文件不是程式,但它們是各指令實際交付的東西:正本的平台中立性決定
|
|
* 轉接檔能不能一份寫到底,段落結構決定下游解析得到什麼。靠人記不牢,用測試釘住。
|
|
*/
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { repoRoot } from './run-script.js';
|
|
|
|
/** 讀一份流程正本 */
|
|
export function readPrompt(name) {
|
|
return readFileSync(join(repoRoot, 'prompts', `${name}.md`), 'utf8');
|
|
}
|
|
|
|
/** 讀一份規則正本 */
|
|
export function readReference(name) {
|
|
return readFileSync(join(repoRoot, 'references', `${name}.md`), 'utf8');
|
|
}
|
|
|
|
/** 讀一份輸出模板 */
|
|
export function readTemplate(name) {
|
|
return readFileSync(join(repoRoot, 'templates', `${name}.md`), 'utf8');
|
|
}
|
|
|
|
/**
|
|
* 正本裡不該出現的字樣:任何一家助理的工具名、目錄名或呼叫語法。
|
|
* 出現任何一個,就代表這份正本已經綁死在某個平台上。
|
|
*/
|
|
export const PLATFORM_SPECIFIC = [
|
|
'AskUserQuestion',
|
|
'Claude',
|
|
'Codex',
|
|
'Antigravity',
|
|
'Copilot',
|
|
'Kiro',
|
|
'OpenCode',
|
|
'oh-my-pi',
|
|
'.claude',
|
|
'.codex',
|
|
];
|
|
|
|
/**
|
|
* 斷言一份正本是平台中立的,且 description 帶上指定前綴。
|
|
* @param {string} prompt 正本內容
|
|
* @param {string} command 指令名,例如 sdlc-plan
|
|
*/
|
|
export function assertNeutralPrompt(prompt, command) {
|
|
const description = prompt.match(/^description:\s*(.+)$/m)?.[1];
|
|
assert.ok(description, '正本需要一行 description 供轉接檔取用');
|
|
assert.ok(
|
|
description.startsWith(`僅由 /${command} 指令叫用。`),
|
|
`description 前綴不符:${description}`,
|
|
);
|
|
|
|
assert.equal(prompt.startsWith('---'), false, '正本不該有 YAML frontmatter,那是轉接檔的事');
|
|
|
|
for (const token of [...PLATFORM_SPECIFIC, `$${command}`]) {
|
|
assert.equal(prompt.includes(token), false, `正本不該出現平台專屬字樣:${token}`);
|
|
}
|
|
}
|