fix(plan): make direct exit discoverable
This commit is contained in:
@@ -11,8 +11,8 @@ buffer
|
|||||||
2| " deepseek-v4-flash • main-session"
|
2| " deepseek-v4-flash • main-session"
|
||||||
style 1-34 dim
|
style 1-34 dim
|
||||||
3| <blank>
|
3| <blank>
|
||||||
4| " Entering plan mode (applies from the next step). "
|
4| " Entering plan mode (applies from the next step). Use /plan off to leave. "
|
||||||
style 1-48 fg=bright-black
|
style 1-72 fg=bright-black
|
||||||
5| <blank>
|
5| <blank>
|
||||||
6| "▌ "
|
6| "▌ "
|
||||||
style 0-0 fg=bright-blue
|
style 0-0 fg=bright-blue
|
||||||
|
|||||||
@@ -87,14 +87,16 @@ describe('tui-agent keyless smoke (real Loader tree in a PTY)', () => {
|
|||||||
const output = await smoke({
|
const output = await smoke({
|
||||||
label: 'tui-agent boot',
|
label: 'tui-agent boot',
|
||||||
actions: [
|
actions: [
|
||||||
{ waitFor: 'main-session-', send: '/plan\r' },
|
{ waitFor: 'main-session-', send: '/plan' },
|
||||||
{ waitFor: 'Entering plan mode (applies from the next step).', send: '/exit\r' },
|
{ waitFor: '[off|message] — Enter or leave plan mode', send: '\r' },
|
||||||
|
{ waitFor: 'Entering plan mode (applies from the next step). Use /plan off to leave.', send: '/exit\r' },
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
expect(output).toContain('DEEPSEEK')
|
expect(output).toContain('DEEPSEEK')
|
||||||
expect(output).toContain('HARNESS')
|
expect(output).toContain('HARNESS')
|
||||||
expect(output).toContain('main-session-')
|
expect(output).toContain('main-session-')
|
||||||
expect(output).toContain('Entering plan mode (applies from the next step).')
|
expect(output).toContain('[off|message] — Enter or leave plan mode')
|
||||||
|
expect(output).toContain('Entering plan mode (applies from the next step). Use /plan off to leave.')
|
||||||
// Borderless: no box-drawing frame around the banner.
|
// Borderless: no box-drawing frame around the banner.
|
||||||
expect(output).not.toContain('╭')
|
expect(output).not.toContain('╭')
|
||||||
expect(output).not.toContain('╮')
|
expect(output).not.toContain('╮')
|
||||||
@@ -127,7 +129,7 @@ describe('tui-agent keyless smoke (real Loader tree in a PTY)', () => {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
expect(output).toContain('I need one decision before I continue.')
|
expect(output).toContain('I need one decision before I continue.')
|
||||||
expect(output).toContain('Entering plan mode (applies from the next step).')
|
expect(output).toContain('Entering plan mode (applies from the next step). Use /plan off to leave.')
|
||||||
expect(output).toContain('Leaving plan mode (applies from the next step).')
|
expect(output).toContain('Leaving plan mode (applies from the next step).')
|
||||||
expect(output).toContain('Default mode confirmed.')
|
expect(output).toContain('Default mode confirmed.')
|
||||||
expect(output).toContain(String.raw`\x1b]2;MODEL_CONTROLLED\x07`)
|
expect(output).toContain(String.raw`\x1b]2;MODEL_CONTROLLED\x07`)
|
||||||
|
|||||||
@@ -228,7 +228,10 @@ export class PlanModeService extends Service {
|
|||||||
}
|
}
|
||||||
this.set(agent, true)
|
this.set(agent, true)
|
||||||
if (message !== '') agent.steer([{ type: 'text', text: message }])
|
if (message !== '') agent.steer([{ type: 'text', text: message }])
|
||||||
return { kind: 'success', text: 'Entering plan mode (applies from the next step).' }
|
return {
|
||||||
|
kind: 'success',
|
||||||
|
text: 'Entering plan mode (applies from the next step). Use /plan off to leave.',
|
||||||
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -553,7 +553,10 @@ describe('/plan', () => {
|
|||||||
expect(await ctx.commands.execute(plainAgent, '/mode', signal)).toBeUndefined()
|
expect(await ctx.commands.execute(plainAgent, '/mode', signal)).toBeUndefined()
|
||||||
expect(await ctx.commands.execute(plainAgent, '/review', signal)).toBeUndefined()
|
expect(await ctx.commands.execute(plainAgent, '/review', signal)).toBeUndefined()
|
||||||
const plain = await ctx.commands.execute(plainAgent, '/plan', signal)
|
const plain = await ctx.commands.execute(plainAgent, '/plan', signal)
|
||||||
expect(plain).toEqual({ kind: 'success', text: 'Entering plan mode (applies from the next step).' })
|
expect(plain).toEqual({
|
||||||
|
kind: 'success',
|
||||||
|
text: 'Entering plan mode (applies from the next step). Use /plan off to leave.',
|
||||||
|
})
|
||||||
expect(ctx.planMode.get(plainAgent)).toEqual({ active: false, pending: true })
|
expect(ctx.planMode.get(plainAgent)).toEqual({ active: false, pending: true })
|
||||||
expect(plainSteer).not.toHaveBeenCalled()
|
expect(plainSteer).not.toHaveBeenCalled()
|
||||||
|
|
||||||
@@ -561,7 +564,10 @@ describe('/plan', () => {
|
|||||||
const messageSteer = vi.fn()
|
const messageSteer = vi.fn()
|
||||||
;(messageAgent as unknown as { steer: typeof messageSteer }).steer = messageSteer
|
;(messageAgent as unknown as { steer: typeof messageSteer }).steer = messageSteer
|
||||||
const plan = await ctx.commands.execute(messageAgent, '/plan draft the migration ', signal)
|
const plan = await ctx.commands.execute(messageAgent, '/plan draft the migration ', signal)
|
||||||
expect(plan).toEqual({ kind: 'success', text: 'Entering plan mode (applies from the next step).' })
|
expect(plan).toEqual({
|
||||||
|
kind: 'success',
|
||||||
|
text: 'Entering plan mode (applies from the next step). Use /plan off to leave.',
|
||||||
|
})
|
||||||
expect(ctx.planMode.get(messageAgent)).toEqual({ active: false, pending: true })
|
expect(ctx.planMode.get(messageAgent)).toEqual({ active: false, pending: true })
|
||||||
expect(messageSteer).toHaveBeenCalledExactlyOnceWith([{ type: 'text', text: 'draft the migration' }])
|
expect(messageSteer).toHaveBeenCalledExactlyOnceWith([{ type: 'text', text: 'draft the migration' }])
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2384,6 +2384,7 @@ export function createTuiChat(
|
|||||||
...ctx.commands.list(agent).map(command => ({
|
...ctx.commands.list(agent).map(command => ({
|
||||||
name: command.name,
|
name: command.name,
|
||||||
description: command.description,
|
description: command.description,
|
||||||
|
...(command.input === undefined ? {} : { argumentHint: command.input.hint }),
|
||||||
})),
|
})),
|
||||||
...skillCommands,
|
...skillCommands,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1706,6 +1706,11 @@ describe('pi-tui chat lifecycle and transcript', () => {
|
|||||||
handler: () => ({ kind: 'error' as const, text: 'plugin error result' }),
|
handler: () => ({ kind: 'error' as const, text: 'plugin error result' }),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
result.terminal.send('/plugin-ch')
|
||||||
|
await tick()
|
||||||
|
expect(result.terminal.output).toContain('<value> — Run a plugin command')
|
||||||
|
result.terminal.send('\x03')
|
||||||
|
|
||||||
result.terminal.send('/plugin-check value ')
|
result.terminal.send('/plugin-check value ')
|
||||||
result.terminal.send('\r')
|
result.terminal.send('\r')
|
||||||
await tick()
|
await tick()
|
||||||
|
|||||||
Reference in New Issue
Block a user