Files
tea-sdlc/test/readme-install.test.js
T
jiantw83andClaude Opus 5 17178f0c4d feat(佈署): 以 npm 裝出 tea-sdlc 指令並產生各平台轉接檔
單一入口 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>
2026-09-17 06:59:37 +00:00

81 lines
3.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* README 的安裝段。
*
* 這一段是使用者照著打的東西,打錯一個字就裝不起來,所以指令要能逐字複製執行,
* 而且不能留下已經不成立的說法——並列一條「照著做不會出現任何指令」的流程等於在說謊。
*/
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { repoRoot } from './helpers/run-script.js';
const readme = () => readFileSync(join(repoRoot, 'README.md'), 'utf8');
const agents = () => readFileSync(join(repoRoot, 'AGENTS.md'), 'utf8');
/** 取出所有 bash 圍欄裡的指令行 */
function commands(text) {
return [...text.matchAll(/```bash\n([\s\S]*?)```/g)]
.flatMap((block) => block[1].split('\n'))
.map((line) => line.trim())
.filter((line) => line !== '' && !line.startsWith('#'));
}
test('安裝以 npm 為唯一建議路徑,指令含完整可複製的 git URL', () => {
const install = commands(readme()).filter((line) => line.startsWith('npm i -g'));
assert.equal(install.length > 0, true, 'README 沒有 npm 安裝指令');
assert.ok(
install.some((line) => line.includes('https://gitea.jsc.idv.tw/plugins/tea-sdlc.git')),
`安裝指令少了完整 git URL:${install.join(' / ')}`,
);
});
test('更新與移除各有完整指令表,順序講清楚先 uninstall 再 npm rm', () => {
const text = readme();
assert.match(text, /npm i -g https:\/\/gitea\.jsc\.idv\.tw\/plugins\/tea-sdlc\.git/);
assert.match(text, /tea-sdlc uninstall/);
assert.match(text, /npm rm -g tea-sdlc/);
// 先砍套件就再也刪不掉那些孤兒轉接檔,順序本身就是內容
assert.ok(
text.indexOf('tea-sdlc uninstall') < text.indexOf('npm rm -g tea-sdlc'),
'uninstall 必須寫在 npm rm -g 之前',
);
});
test('明寫不要用 npm update -g,並說出為什麼', () => {
const text = readme();
assert.match(text, /npm update -g/);
const at = text.indexOf('npm update -g');
assert.match(text.slice(at - 200, at + 200), /不要|別/);
});
test('四個子指令在 README 上都有用途說明', () => {
const text = readme();
for (const name of ['install', 'uninstall', 'prompt', 'status']) {
assert.match(text, new RegExp(`tea-sdlc ${name}`), `README 沒有交代 ${name}`);
}
});
test('七套 marketplace 流程移進附錄保留,內容沒有被刪掉', () => {
const text = readme();
const appendix = text.slice(text.indexOf('## 附錄'));
assert.ok(text.includes('## 附錄'), 'README 沒有附錄');
for (const line of ['claude plugin marketplace add', 'codex plugin marketplace add', 'agy plugin install']) {
assert.ok(appendix.includes(line), `附錄少了 ${line}`);
}
});
test('模組邊界表指得到實際存在的檔案', () => {
const text = agents();
assert.match(text, /`bin\/tea-sdlc\.js`/);
assert.match(text, /`scripts\/install\.js`/);
assert.equal(/\| `install\.js` \|/.test(text), false, '表上還留著已經不存在的根目錄 install.js');
});