import { describe, expect, test } from 'claude-code/testing' import { resolveConfig } from './config' import { buildRules, SECTION_ID } from './rules' const cfg = (o: Record = {}) => resolveConfig({ defaultCharacter: 'sao-asuna', ...o }) describe('buildRules', () => { test('強度 0 與未選角色不注入', () => { expect(buildRules(cfg({ intensity: '0' }))).toBeNull() expect(buildRules(resolveConfig({}))).toBeNull() }) test('強度 1 只換稱呼與句尾,沒有氣泡與旁白', () => { const t = buildRules(cfg({ intensity: '1' }))! expect(t).toContain('只換稱呼與句尾') expect(t).not.toContain('前後各一個氣泡') expect(t).not.toContain('最前面再加一行動作旁白') }) test('強度 2 前後各一個氣泡,無旁白', () => { const t = buildRules(cfg())! expect(t).toContain('前後各一個氣泡') expect(t).toContain('最多一兩句') expect(t).toContain('不加動作旁白') }) test('強度 3 加動作旁白', () => { const t = buildRules(cfg({ intensity: '3' }))! expect(t).toContain('前後各一個氣泡') expect(t).toContain('最前面再加一行動作旁白') expect(t).not.toContain('不加動作旁白') }) test('稱呼依角色,設定可覆寫', () => { expect(buildRules(cfg())!).toContain('「桐人」') expect(buildRules(cfg(), 'sao-suguha')!).toContain('「哥哥」') expect(buildRules(cfg({ address: '阿桐' }))!).toContain('「阿桐」') }) test('各強度都保留安全規則:先用一句清楚的話,需確認時省略收尾氣泡', () => { for (const intensity of ['1', '2', '3']) { const t = buildRules(cfg({ intensity }))! expect(t).toContain('第一句用中性、清楚的話') expect(t).toContain('不加收尾的對話氣泡') } }) test('角色語氣不進程式碼、commit 與檔案內容', () => { expect(buildRules(cfg())!).toContain('程式碼、commit 訊息與檔案內容保持中性') }) }) describe('prompt.compose hook', () => { const input = { model: 'm', promptModel: 'm', surfaces: [], tools: [], outputStyle: null, traits: [] } const base = { sections: [{ id: 'intro', text: 'x', scope: 'shared' as const }] } test('在原有段落後加入規則段落', { options: { defaultCharacter: 'sao-asuna', intensity: '2' } }, async ($, on) => { on('prompt.compose', ($, e, next) => base) const r = await $.prompt.compose(input) expect(r.sections.at(-1)?.id).toBe(SECTION_ID) expect(r.sections.at(-1)?.scope).toBe('session') expect(r.sections[0]?.id).toBe('intro') }) test('強度 0 不加段落', { options: { defaultCharacter: 'sao-asuna', intensity: '0' } }, async ($, on) => { on('prompt.compose', ($, e, next) => base) const r = await $.prompt.compose(input) expect(r.sections.some(s => s.id === SECTION_ID)).toBe(false) }) })