單一入口 bin/tea-sdlc.js 認四個子指令。第一個位置參數是子指令,其餘 argv 原樣 交出去——既有的 flag 解析拒絕位置參數,所以子指令必須在那之前就被取走。 轉接檔裡沒有路徑,只有一句 tea-sdlc prompt --name <指令名>。正本在哪由 PATH 上 的 tea-sdlc 自己回推:fnm 把 Node 版號寫進全域安裝路徑,寫死路徑的話升一次 Node,七個平台的轉接檔會同時指向不存在的檔案,而且不會有任何錯誤訊息。 prompt 是全專案唯一輸出非 JSON 的路徑,理由只有一個:它的輸出要餵給模型讀。 失敗仍走 envelope——成功是內容,失敗才需要結構。 status 的 ok 不兼差表達環境好壞,健康與否放在 data.healthy:呼叫端要分得出 「status 掛了」與「status 成功查到你環境有問題」。 install 只寫進偵測得到的平台;缺 git/tea 只警告不中止,因為那兩個完全不影響 轉接檔產生,硬擋等於逼使用者為了裝 plugin 先去裝 tea。uninstall 只刪帶產生標記 的檔案,使用者自己寫的同名檔案一律留著並在輸出裡交代。裝哪些指令以 prompts/ 裡 實際存在的正本為準,不是寫死的六個名字——裝出指向不存在正本的轉接檔,使用者只會 看到 PROMPT_NOT_FOUND。 流程正本的 description 前綴在抄進轉接檔之前就檢查:有三個平台關不掉自動觸發, 全靠那句話把 description 窄到不會被誤判,不能等使用者發現誤觸才知道漏了。 議題 #26 #27 #28 #29 #17 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
55 lines
2.1 KiB
JavaScript
55 lines
2.1 KiB
JavaScript
/**
|
||
* 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}`,
|
||
);
|
||
}
|