/** * /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), /重新抽取一次拿到更新後的描述/); }); }