/** * prompt 子指令:把一份流程正本原樣交出去。 * * 轉接檔裡沒有路徑,只有一句「執行 tea-sdlc prompt --name sdlc-plan」。正本在哪, * 由 PATH 上的 tea-sdlc 自己從檔案位置回推——Node 升級、換版本管理器、改 npm prefix * 都不會讓轉接檔指向不存在的檔案。 * * 用法(由 bin/tea-sdlc.js 轉入): * tea-sdlc prompt --name sdlc-plan [--adapter-version 0.0.1] */ import { existsSync, readFileSync } from 'node:fs'; import { join } from 'node:path'; import { RawText, ScriptError, checkPluginLayout, packageVersion, parseFlags, promptsDir, } from './lib.js'; /** 指令名的合法樣子。擋的是路徑跳脫,順便把打錯的名字擋在讀檔之前。 */ const NAME = /^[a-z][a-z0-9-]*$/; /** * @param {string[]} argv bin 取走子指令之後剩下的參數 * @returns {import('./lib.js').RawText} 正本原文;版本不符時前面多一行警告 */ export function runPrompt(argv) { const flags = parseFlags(argv, { required: ['name'], optional: ['adapter-version'] }); checkPluginLayout(); const name = String(flags.name); if (!NAME.test(name)) { throw new ScriptError('BAD_PROMPT_NAME', `--name 只接受小寫英數與連字號,收到的是 ${name}`); } const path = join(promptsDir(), `${name}.md`); if (!existsSync(path)) { throw new ScriptError('PROMPT_NOT_FOUND', `沒有名為 ${name} 的流程正本(找不到 ${path})`); } const text = readFileSync(path, 'utf8'); const adapter = flags['adapter-version']; const current = packageVersion(); if (adapter === undefined || adapter === current) return new RawText(text); // 正本仍然照給。轉接檔過時只是清單可能不齊,不是流程不能跑; // 警告放在最前面,是因為那是模型每次叫用必定會讀到的位置,不依賴使用者記得去查 status。 return new RawText( `> ⚠️ 這份轉接檔是 tea-sdlc ${adapter} 產生的,目前安裝的是 ${current};` + `請重跑 \`tea-sdlc install\` 更新轉接檔。\n\n${text}`, ); }