import { describe, expect, it } from 'vitest' import type { NativeChatMessage } from './native-chat-types' import { parseNativeChatCommandEnvelope, surfaceSkillInvocationUserTurns } from './native-chat-command-envelope' const CATALOG = new Set(['clear', 'model']) function userTurn(text: string, overrides: Partial = {}): NativeChatMessage { return { id: 'user-1', role: 'user', blocks: [{ type: 'text', text }], timestamp: 100, source: 'transcript', ...overrides } } describe('parseNativeChatCommandEnvelope', () => { it('parses name-first and message-first envelope orderings', () => { expect( parseNativeChatCommandEnvelope( '/model\n model\n ' ) ).toEqual({ name: '/model', args: '' }) expect( parseNativeChatCommandEnvelope( 'ce-brainstorm\n/ce-brainstorm\nimprove the picker' ) ).toEqual({ name: '/ce-brainstorm', args: 'improve the picker' }) }) it('ignores ordinary prompts and non-leading envelope tags', () => { expect(parseNativeChatCommandEnvelope('deploy the app')).toBeNull() expect(parseNativeChatCommandEnvelope('see /x')).toBeNull() expect(parseNativeChatCommandEnvelope('/x')).toBeNull() }) }) describe('surfaceSkillInvocationUserTurns', () => { it('renders a skill-invocation envelope as the literal user token', () => { const messages = [ userTurn( 'ce-brainstorm\n/ce-brainstorm\nimprove the picker' ) ] const out = surfaceSkillInvocationUserTurns(messages, CATALOG) expect(out[0].blocks).toEqual([{ type: 'text', text: '/ce-brainstorm improve the picker' }]) expect(out[0].id).toBe('user-1') }) it('shortens plugin-qualified names back to the token the user sent', () => { const messages = [ userTurn( 'compound-engineering:ce-brainstorm\n/compound-engineering:ce-brainstorm\nhi' ) ] const out = surfaceSkillInvocationUserTurns(messages, CATALOG) expect(out[0].blocks).toEqual([{ type: 'text', text: '/ce-brainstorm hi' }]) }) it('never hides a plugin skill whose short name shadows a catalog command', () => { const messages = [ userTurn('/some-plugin:clear\n') ] const out = surfaceSkillInvocationUserTurns(messages, CATALOG) expect(out[0].blocks).toEqual([{ type: 'text', text: '/clear' }]) }) it('leaves catalog command envelopes for the noise filter and Ran marker', () => { const messages = [ userTurn('/model\n') ] expect(surfaceSkillInvocationUserTurns(messages, CATALOG)).toBe(messages) }) it('does not touch assistant turns, plain prompts, or non-text blocks', () => { const messages: NativeChatMessage[] = [ userTurn('hello there'), userTurn('/skill', { id: 'user-2', role: 'assistant' }), userTurn('/skill', { id: 'user-3', blocks: [ { type: 'text', text: '/skill' }, { type: 'image-ref', path: '/tmp/a.png' } ] }) ] expect(surfaceSkillInvocationUserTurns(messages, CATALOG)).toBe(messages) }) })