feat(plan): add direct plan exit command
This commit is contained in:
@@ -546,7 +546,7 @@ describe('/plan', () => {
|
||||
const plainSteer = vi.fn()
|
||||
;(plainAgent as unknown as { steer: typeof plainSteer }).steer = plainSteer
|
||||
expect(ctx.commands.list(plainAgent)).toEqual([
|
||||
{ name: 'plan', description: 'Enter plan mode', input: { hint: '[message]' } },
|
||||
{ name: 'plan', description: 'Enter or leave plan mode', input: { hint: '[off|message]' } },
|
||||
])
|
||||
|
||||
const signal = new AbortController().signal
|
||||
@@ -566,6 +566,42 @@ describe('/plan', () => {
|
||||
expect(messageSteer).toHaveBeenCalledExactlyOnceWith([{ type: 'text', text: 'draft the migration' }])
|
||||
})
|
||||
|
||||
it('leaves active plan mode, cancels a pending entry, and treats inactive exit as idempotent', async () => {
|
||||
const ctx = await setup()
|
||||
await ctx.plugin(CommandService)
|
||||
await new Promise(resolve => setImmediate(resolve))
|
||||
const signal = new AbortController().signal
|
||||
|
||||
const inactive = await agentWithSession(ctx, 'inactive-plan-command')
|
||||
expect(await ctx.commands.execute(inactive, '/plan off', signal))
|
||||
.toEqual({ kind: 'success', text: 'Plan mode is already inactive.' })
|
||||
expect(ctx.planMode.get(inactive)).toEqual({ active: false })
|
||||
|
||||
const entering = await agentWithSession(ctx, 'entering-plan-command')
|
||||
const enteringSteer = vi.fn()
|
||||
;(entering as unknown as { steer: typeof enteringSteer }).steer = enteringSteer
|
||||
await ctx.commands.execute(entering, '/plan', signal)
|
||||
expect(await ctx.commands.execute(entering, '/plan off', signal))
|
||||
.toEqual({ kind: 'success', text: 'Plan mode entry cancelled.' })
|
||||
expect(ctx.planMode.get(entering)).toEqual({ active: false, pending: false })
|
||||
expect(enteringSteer).not.toHaveBeenCalled()
|
||||
await boundary(ctx, entering, 'turn/start')
|
||||
expect(ctx.planMode.get(entering)).toEqual({ active: false })
|
||||
expect(entering.session.events.some(event => event.type === 'plan/mode')).toBe(false)
|
||||
|
||||
const active = await agentWithSession(ctx, 'active-plan-command', { active: true })
|
||||
const activeSteer = vi.fn()
|
||||
;(active as unknown as { steer: typeof activeSteer }).steer = activeSteer
|
||||
expect(await ctx.commands.execute(active, '/plan off', signal))
|
||||
.toEqual({ kind: 'success', text: 'Leaving plan mode (applies from the next step).' })
|
||||
expect(ctx.planMode.get(active)).toEqual({ active: true, pending: false })
|
||||
expect(await ctx.commands.execute(active, '/plan off', signal))
|
||||
.toEqual({ kind: 'success', text: 'Leaving plan mode (applies from the next step).' })
|
||||
expect(activeSteer).not.toHaveBeenCalled()
|
||||
await boundary(ctx, active, 'turn/start')
|
||||
expect(ctx.planMode.get(active)).toEqual({ active: false })
|
||||
})
|
||||
|
||||
it('removes the contributed command when the plan-mode plugin is disposed', async () => {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SystemPrompt)
|
||||
|
||||
Reference in New Issue
Block a user