mirror of
https://github.com/NanmiCoder/cc-haha
synced 2026-07-18 13:23:33 +08:00
Hide unfinished goal command entrypoints
The goal implementation is being kept in the tree for later redesign, but the CLI and desktop slash-command surfaces should not advertise or route new users into it while the long-running goal experience is incomplete. Existing transcript parsing and goal event rendering remain intact so historical sessions still load. Constraint: Keep the implementation code available for future iteration while removing discoverable entrypoints. Confidence: high Scope-risk: narrow Directive: Do not re-expose /goal until the persistent goal/runtime design is revisited. Tested: bun test src/commands/headless.test.ts Tested: cd desktop && bun run test -- composerUtils.test.ts pages.test.tsx Tested: NODE_ENV=test ANTHROPIC_API_KEY=dummy bun -e getCommands assertion for hidden goal command
This commit is contained in:
parent
66fd78f0c5
commit
8ecc757729
@ -159,7 +159,7 @@ describe('Content-only pages render without errors', () => {
|
||||
expect(screen.queryByText('/internal-only')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('EmptySession shows /goal as one command with argument hints, not pseudo subcommands', async () => {
|
||||
it('EmptySession does not expose the paused /goal command', async () => {
|
||||
vi.mocked(skillsApi.list).mockResolvedValueOnce({ skills: [] })
|
||||
|
||||
render(<EmptySession />)
|
||||
@ -168,9 +168,12 @@ describe('Content-only pages render without errors', () => {
|
||||
target: { value: '/goal', selectionStart: 5 },
|
||||
})
|
||||
|
||||
expect(await screen.findAllByText('/goal')).toHaveLength(2)
|
||||
expect(screen.getByText('[<condition> | clear]')).toBeInTheDocument()
|
||||
expect(screen.getByText('Set a completion goal')).toBeInTheDocument()
|
||||
await waitFor(() => {
|
||||
expect(skillsApi.list).toHaveBeenCalled()
|
||||
})
|
||||
expect(screen.queryByText('/goal', { selector: 'span' })).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('[<condition> | clear]')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('Set a completion goal')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('/goal status')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('/goal --tokens')).not.toBeInTheDocument()
|
||||
})
|
||||
@ -625,7 +628,7 @@ describe('Content-only pages render without errors', () => {
|
||||
expect(screen.getByText('Slash commands')).toBeInTheDocument()
|
||||
expect(screen.getByText('/clear')).toBeInTheDocument()
|
||||
expect(screen.getByText('/cost')).toBeInTheDocument()
|
||||
expect(screen.getByText('14 more commands available. Type / to search the full command list.')).toBeInTheDocument()
|
||||
expect(screen.getByText('13 more commands available. Type / to search the full command list.')).toBeInTheDocument()
|
||||
|
||||
resetPageStores()
|
||||
})
|
||||
|
||||
@ -66,7 +66,7 @@ describe('composerUtils', () => {
|
||||
expect(
|
||||
mergeSlashCommands([
|
||||
{
|
||||
name: 'goal',
|
||||
name: 'compact',
|
||||
description: '',
|
||||
argumentHint: '',
|
||||
},
|
||||
@ -74,24 +74,18 @@ describe('composerUtils', () => {
|
||||
).toEqual(
|
||||
expect.arrayContaining([
|
||||
{
|
||||
name: 'goal',
|
||||
description: 'Set a completion goal',
|
||||
argumentHint: '[<condition> | clear]',
|
||||
name: 'compact',
|
||||
description: 'Compact conversation context',
|
||||
},
|
||||
]),
|
||||
)
|
||||
})
|
||||
|
||||
it('keeps /goal as a single command with argument hints instead of pseudo subcommands', () => {
|
||||
it('does not expose paused /goal fallback commands', () => {
|
||||
const commands = filterSlashCommands(mergeSlashCommands([]), 'goal')
|
||||
|
||||
expect(
|
||||
commands.map((command) => command.name),
|
||||
).toEqual(['goal'])
|
||||
expect(commands[0]).toMatchObject({
|
||||
description: 'Set a completion goal',
|
||||
argumentHint: '[<condition> | clear]',
|
||||
})
|
||||
expect(commands.map((command) => command.name)).toEqual([])
|
||||
expect(mergeSlashCommands([]).map((command) => command.name)).not.toContain('goal')
|
||||
expect(mergeSlashCommands([]).map((command) => command.name)).not.toContain('goal status')
|
||||
expect(mergeSlashCommands([]).map((command) => command.name)).not.toContain('goal --tokens')
|
||||
})
|
||||
|
||||
@ -24,11 +24,6 @@ export const FALLBACK_SLASH_COMMANDS = [
|
||||
...SETTINGS_SLASH_COMMANDS.map(({ name, description }) => ({ name, description })),
|
||||
{ name: 'compact', description: 'Compact conversation context' },
|
||||
{ name: 'clear', description: 'Clear conversation history' },
|
||||
{
|
||||
name: 'goal',
|
||||
description: 'Set a completion goal',
|
||||
argumentHint: '[<condition> | clear]',
|
||||
},
|
||||
{ name: 'review', description: 'Review code changes' },
|
||||
{ name: 'commit', description: 'Create a git commit' },
|
||||
{ name: 'pr', description: 'Create a pull request' },
|
||||
|
||||
@ -6,7 +6,6 @@ import btw from './commands/btw/index.js'
|
||||
import goodClaude from './commands/good-claude/index.js'
|
||||
import issue from './commands/issue/index.js'
|
||||
import feedback from './commands/feedback/index.js'
|
||||
import goal from './commands/goal/index.js'
|
||||
import clear from './commands/clear/index.js'
|
||||
import color from './commands/color/index.js'
|
||||
import commit from './commands/commit.js'
|
||||
@ -304,7 +303,6 @@ const COMMANDS = memoize((): Command[] => [
|
||||
tag,
|
||||
theme,
|
||||
feedback,
|
||||
goal,
|
||||
review,
|
||||
ultrareview,
|
||||
rewind,
|
||||
|
||||
@ -3,13 +3,13 @@ import type { Command } from '../types/command.js'
|
||||
import { filterCommandsForHeadlessMode } from './headless.js'
|
||||
|
||||
describe('filterCommandsForHeadlessMode', () => {
|
||||
test('keeps /goal without exposing other local-jsx UI commands', () => {
|
||||
test('keeps non-interactive commands without exposing local-jsx UI commands', () => {
|
||||
const commands = [
|
||||
{
|
||||
type: 'local-jsx',
|
||||
supportsNonInteractive: true,
|
||||
name: 'goal',
|
||||
description: 'Set a goal',
|
||||
name: 'cost',
|
||||
description: 'Show cost',
|
||||
load: async () => ({ call: async () => null }),
|
||||
},
|
||||
{
|
||||
@ -40,7 +40,7 @@ describe('filterCommandsForHeadlessMode', () => {
|
||||
] satisfies Command[]
|
||||
|
||||
expect(filterCommandsForHeadlessMode(commands).map(command => command.name)).toEqual([
|
||||
'goal',
|
||||
'cost',
|
||||
'review',
|
||||
])
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user