import { describe, expect, it } from 'vitest' import { getPermissionModesForFlavor } from '@hapi/protocol/modes' import { findCodexCustomPromptExpansion, findUnsupportedCodexBuiltinSlashCommand, getBuiltinSlashCommands, mergeSlashCommands } from './codexSlashCommands' describe('getBuiltinSlashCommands', () => { it('exposes HAPI-supported codex built-ins in remote web mode', () => { expect(getBuiltinSlashCommands('codex').map((command) => command.name)).toEqual(expect.arrayContaining([ 'clear', 'compact', 'goal', 'plan', 'status', 'execute', 'effort', 'permission', ])) }) it('exposes Cursor pass-through builtins', () => { expect(getBuiltinSlashCommands('cursor').map((command) => command.name)).toEqual( ['compress'] ) }) it.each(['pi', 'kimi'])('does not fall back to Claude commands for %s', (flavor) => { expect(getBuiltinSlashCommands(flavor)).toEqual([]) }) it('includes debug only in Cursor permission modes', () => { expect(getPermissionModesForFlavor('cursor')).toContain('debug') expect(getPermissionModesForFlavor('claude')).not.toContain('debug') }) }) describe('mergeSlashCommands', () => { it('lets custom commands override same-name built-ins', () => { const commands = mergeSlashCommands([ { name: 'clear', source: 'builtin' }, { name: 'compact', source: 'builtin' }, { name: 'clear', source: 'project', content: 'project clear prompt' } ]) expect(commands).toEqual([ { name: 'compact', source: 'builtin' }, { name: 'clear', source: 'project', content: 'project clear prompt' } ]) }) it('keeps API-provided built-ins while de-duplicating by name', () => { const commands = mergeSlashCommands([ { name: 'clear', source: 'builtin' }, { name: 'status', source: 'builtin' }, { name: 'help', source: 'builtin' }, { name: 'status', source: 'builtin', description: 'Captured status' }, { name: 'project-only', source: 'project', content: 'Project prompt' } ]) expect(commands).toEqual([ { name: 'clear', source: 'builtin' }, { name: 'help', source: 'builtin' }, { name: 'status', source: 'builtin', description: 'Captured status' }, { name: 'project-only', source: 'project', content: 'Project prompt' } ]) }) }) describe('findCodexCustomPromptExpansion', () => { it('expands exact custom codex prompt commands', () => { expect(findCodexCustomPromptExpansion(' /clear ', [ { name: 'clear', source: 'builtin' }, { name: 'clear', source: 'project', content: 'custom clear prompt' } ])).toBe('custom clear prompt') }) it('ignores built-ins and commands with arguments', () => { const commands = [ { name: 'compact', source: 'project', content: 'custom compact prompt' } ] as const expect(findCodexCustomPromptExpansion('/compact now', commands)).toBeNull() expect(findCodexCustomPromptExpansion('/clear', [ { name: 'clear', source: 'builtin' } ])).toBeNull() }) }) describe('findUnsupportedCodexBuiltinSlashCommand', () => { it('detects unsupported codex built-ins', () => { expect(findUnsupportedCodexBuiltinSlashCommand(' /diff ', [])).toBe('diff') }) it('ignores regular messages and unknown commands', () => { expect(findUnsupportedCodexBuiltinSlashCommand('show me status', [])).toBeNull() expect(findUnsupportedCodexBuiltinSlashCommand('/custom-status', [])).toBeNull() }) it('does not block custom commands that override the same name', () => { expect(findUnsupportedCodexBuiltinSlashCommand('/status', [ { name: 'status', source: 'project', content: 'project status prompt' } ])).toBeNull() }) })