Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
152 lines
6.7 KiB
JavaScript
152 lines
6.7 KiB
JavaScript
/**
|
|
* /sdlc-sync 的流程正本,以及另外兩份正本的「接回」那一段。
|
|
*
|
|
* 這個指令的價值在於「描述不再騙人」,而三件關鍵事只有正本做得到:挑出哪些留言真的是
|
|
* 決策、寫回去之前讓使用者點頭、以及略過的那幾則要保持未標記。寫漏任何一件,
|
|
* 描述就會繼續過期,或者有決策被靜靜吞掉。
|
|
*/
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { assertNeutralPrompt, readPrompt } from './helpers/prompt-doc.js';
|
|
|
|
const prompt = readPrompt('sdlc-sync');
|
|
const steps = prompt.slice(prompt.indexOf('## 1.'), prompt.indexOf('## 邊界'));
|
|
|
|
test('正本平台中立,description 前綴正確', () => {
|
|
assertNeutralPrompt(prompt, 'sdlc-sync');
|
|
});
|
|
|
|
test('兩種議題各自指名對應的抽取腳本', () => {
|
|
assert.match(steps, /issue-extract/);
|
|
assert.match(steps, /wp-extract/);
|
|
assert.match(steps, /需求議題.*工作包議題|工作包議題.*需求議題/s);
|
|
});
|
|
|
|
test('留言內容另外拿,並說明為什麼抽取契約不夠', () => {
|
|
assert.match(steps, /pr-comments/);
|
|
assert.match(steps, /只給數字不給內容/);
|
|
});
|
|
|
|
test('說明那支腳本議題與 PR 都收得下,不再宣稱「PR 也是 issue」', () => {
|
|
assert.match(steps, /議題與 PR 都收得下/);
|
|
assert.equal(steps.includes('Gitea 的 PR 也是 issue'), false, '反過來說才對:每個 PR 都是議題');
|
|
});
|
|
|
|
test('已處理認的是自己打的 +1', () => {
|
|
assert.match(steps, /自己打的/);
|
|
assert.match(steps, /我同意/);
|
|
});
|
|
|
|
test('略過會讓計數停在大於 0,這件事要講明白', () => {
|
|
const section = steps.slice(steps.indexOf('## 5.'));
|
|
assert.match(section, /停在大於 0/);
|
|
assert.match(section, /每次開始時都會再停一次/);
|
|
assert.match(section, /他選了略過/, '要讓使用者分得出「沒整併乾淨」與「選了略過」');
|
|
});
|
|
|
|
test('已標記過的留言跳過', () => {
|
|
assert.match(steps, /已經標記過的留言不再處理|已處理.*跳過/s);
|
|
});
|
|
|
|
// ── 挑決策 ─────────────────────────────────────────────────────────
|
|
|
|
test('要整併與不整併各有判斷依據,不是只給兩個詞', () => {
|
|
assert.match(steps, /\*\*要整併\*\* — .{10,}/);
|
|
assert.match(steps, /\*\*不整併\*\* — .{10,}/);
|
|
});
|
|
|
|
test('判斷不了時當成要整併,並說出漏掉的代價', () => {
|
|
assert.match(steps, /判斷不了的\*\*當成要整併\*\*/);
|
|
assert.match(steps, /描述就會繼續騙後面的人/);
|
|
});
|
|
|
|
// ── 先點頭再寫 ─────────────────────────────────────────────────────
|
|
|
|
test('寫回去之前要列出方案給使用者看', () => {
|
|
assert.match(steps, /先列出來再動手/);
|
|
assert.match(steps, /哪一段/);
|
|
assert.match(steps, /改完長什麼樣/);
|
|
});
|
|
|
|
test('一次問一題,且略過的會保持未標記', () => {
|
|
assert.match(steps, /一次問一題/);
|
|
assert.match(steps, /略過的留言保持未標記/);
|
|
assert.match(steps, /下次執行還會被提出來/);
|
|
});
|
|
|
|
test('說明了這一步是描述的最後一道關卡', () => {
|
|
assert.match(steps, /最後一道關卡/);
|
|
assert.match(steps, /拿它當事實/);
|
|
});
|
|
|
|
// ── 寫回 ───────────────────────────────────────────────────────────
|
|
|
|
test('指名 comments-merge,並要求先試跑', () => {
|
|
assert.match(steps, /comments-merge\.js/);
|
|
assert.match(steps, /--dry-run/);
|
|
});
|
|
|
|
test('--content-file 的內容是整段,且說明標題那一行不含在內', () => {
|
|
assert.match(steps, /那一段改完的完整內容/);
|
|
assert.match(steps, /不含 `## 標題` 那一行/);
|
|
});
|
|
|
|
test('--merged 只放真的併進去的,並說出放錯的後果', () => {
|
|
assert.match(steps, /只放\*\*真的被併進這一段\*\*/);
|
|
assert.match(steps, /再也\n?不會被提出來|再也不會被提出來/);
|
|
});
|
|
|
|
test('SECTION_NOT_FOUND 的處置是回頭確認,不是硬塞別的段落', () => {
|
|
assert.match(steps, /SECTION_NOT_FOUND/);
|
|
assert.match(steps, /不要改用別的段落硬塞/);
|
|
});
|
|
|
|
// ── 回報 ───────────────────────────────────────────────────────────
|
|
|
|
test('回報要列出略過的那幾則', () => {
|
|
const section = steps.slice(steps.indexOf('## 5.'));
|
|
assert.match(section, /略過的那幾則是哪些/);
|
|
assert.match(section, /下次還會出現/);
|
|
});
|
|
|
|
// ── 接回原本的指令 ─────────────────────────────────────────────────
|
|
|
|
test('整併完自動接回,不要求使用者重打指令', () => {
|
|
const section = prompt.slice(prompt.indexOf('## 接回原本的指令'));
|
|
assert.match(section, /直接接回去/);
|
|
assert.match(section, /不要要求使用者重打一次/);
|
|
});
|
|
|
|
test('接回之前要重新抽取,並說明為什麼', () => {
|
|
const section = prompt.slice(prompt.indexOf('## 接回原本的指令'));
|
|
assert.match(section, /先重跑一次抽取/);
|
|
assert.match(section, /這一整段就白做了/);
|
|
});
|
|
|
|
// ── 邊界 ───────────────────────────────────────────────────────────
|
|
|
|
test('邊界列出不做的事,含不刪改留言', () => {
|
|
const boundary = prompt.slice(prompt.indexOf('## 邊界'));
|
|
assert.match(boundary, /不自行決定要不要整併/);
|
|
assert.match(boundary, /不整份重寫描述/);
|
|
assert.match(boundary, /不標記略過的留言/);
|
|
assert.match(boundary, /不刪除、不編輯任何留言/);
|
|
assert.match(boundary, /誰說過什麼的紀錄/, '要說出為什麼留言不能動');
|
|
});
|
|
|
|
// ── 另外兩份正本的接回 ─────────────────────────────────────────────
|
|
|
|
for (const name of ['sdlc-analyze', 'sdlc-feat']) {
|
|
test(`${name} 偵測到未整併留言時會轉去整併,並自動接回`, () => {
|
|
const other = readPrompt(name);
|
|
assert.match(other, /未處理留言數/);
|
|
assert.match(other, /直接走 `\/sdlc-sync` 的流程/, `${name} 要真的轉過去,不是叫人自己跑`);
|
|
assert.match(other, /自動接回這裡/);
|
|
assert.match(other, /不要要求使用者重打指令/);
|
|
});
|
|
|
|
test(`${name} 接回前要重新抽取一次`, () => {
|
|
assert.match(readPrompt(name), /重新抽取一次拿到更新後的描述/);
|
|
});
|
|
}
|