-
Notifications
You must be signed in to change notification settings - Fork 519
Expand file tree
/
Copy pathbash-mode.test.ts
More file actions
397 lines (310 loc) · 12.6 KB
/
bash-mode.test.ts
File metadata and controls
397 lines (310 loc) · 12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
import { describe, test, expect, beforeEach, mock } from 'bun:test'
/**
* Tests for bash mode functionality in the CLI.
*
* Bash mode is entered when user types '!' and allows running terminal commands.
* The '!' is displayed in a red column but not stored in the input value.
*
* Key behaviors:
* 1. Typing '!' enters bash mode and clears input to ''
* 2. In bash mode, input is stored WITHOUT '!' prefix
* 3. Backspace at cursor position 0 exits bash mode (even with input)
* 4. Submission prepends '!' to the command
*/
describe('bash-mode', () => {
describe('entering bash mode', () => {
test('typing exactly "!" enters bash mode and clears input', () => {
const setBashMode = mock(() => {})
const setInputValue = mock((value: any) => {})
// Simulate user typing '!'
const inputValue = { text: '!', cursorPosition: 1, lastEditDueToNav: false }
const isBashMode = false
// This simulates the handleInputChange logic
const userTypedBang = !isBashMode && inputValue.text === '!'
if (userTypedBang) {
setBashMode()
const newValue = {
text: '',
cursorPosition: 0,
lastEditDueToNav: inputValue.lastEditDueToNav,
}
setInputValue(newValue)
}
expect(setBashMode).toHaveBeenCalled()
expect(setInputValue).toHaveBeenCalled()
})
test('typing "!ls" does NOT enter bash mode (not exactly "!")', () => {
const setBashMode = mock(() => {})
const setInputValue = mock((value: any) => {})
// Simulate user typing '!ls'
const inputValue = { text: '!ls', cursorPosition: 3, lastEditDueToNav: false }
const isBashMode = false
const userTypedBang = !isBashMode && inputValue.text === '!'
if (userTypedBang) {
setBashMode()
const newValue = {
text: '',
cursorPosition: 0,
lastEditDueToNav: inputValue.lastEditDueToNav,
}
setInputValue(newValue)
}
expect(setBashMode).not.toHaveBeenCalled()
expect(setInputValue).not.toHaveBeenCalled()
})
test('typing "!" when already in bash mode does nothing special', () => {
const setBashMode = mock(() => {})
const setInputValue = mock((value: any) => {})
const inputValue = { text: '!', cursorPosition: 1, lastEditDueToNav: false }
const isBashMode = true
const userTypedBang = !isBashMode && inputValue.text === '!'
if (userTypedBang) {
setBashMode()
const newValue = {
text: '',
cursorPosition: 0,
lastEditDueToNav: inputValue.lastEditDueToNav,
}
setInputValue(newValue)
}
// Should not trigger because already in bash mode
expect(setBashMode).not.toHaveBeenCalled()
expect(setInputValue).not.toHaveBeenCalled()
})
})
describe('exiting bash mode', () => {
test('backspace at cursor position 0 exits bash mode', () => {
const setBashMode = mock(() => {})
// Simulate backspace key press in bash mode at cursor position 0
const isBashMode = true
const cursorPosition = 0
const key = { name: 'backspace' }
// This simulates the handleSuggestionMenuKey logic
if (isBashMode && cursorPosition === 0 && key.name === 'backspace') {
setBashMode()
}
expect(setBashMode).toHaveBeenCalled()
})
test('backspace at cursor position 0 with non-empty input DOES exit bash mode', () => {
const setBashMode = mock(() => {})
const isBashMode = true
const inputValue: string = 'ls'
const cursorPosition = 0
const key = { name: 'backspace' }
if (isBashMode && cursorPosition === 0 && key.name === 'backspace') {
setBashMode()
}
// Should exit even though input is not empty, because cursor is at position 0
expect(setBashMode).toHaveBeenCalled()
})
test('backspace at cursor position > 0 does NOT exit bash mode', () => {
const setBashMode = mock(() => {})
const isBashMode = true
const cursorPosition: number = 2
const key = { name: 'backspace' }
if (isBashMode && cursorPosition === 0 && key.name === 'backspace') {
setBashMode()
}
// Should not exit because cursor is not at position 0
expect(setBashMode).not.toHaveBeenCalled()
})
test('other keys at cursor position 0 do NOT exit bash mode', () => {
const setBashMode = mock(() => {})
const isBashMode = true
const cursorPosition = 0
const key = { name: 'a' } // Regular key press
if (isBashMode && cursorPosition === 0 && key.name === 'backspace') {
setBashMode()
}
// Should not exit because key is not backspace
expect(setBashMode).not.toHaveBeenCalled()
})
test('backspace when NOT in bash mode does nothing to bash mode', () => {
const setBashMode = mock(() => {})
const isBashMode = false
const cursorPosition = 0
const key = { name: 'backspace' }
if (isBashMode && cursorPosition === 0 && key.name === 'backspace') {
setBashMode()
}
// Should not trigger because not in bash mode
expect(setBashMode).not.toHaveBeenCalled()
})
})
describe('bash mode input storage', () => {
test('input value does NOT include "!" prefix while in bash mode', () => {
// When user types "ls" in bash mode, inputValue.text should be "ls", not "!ls"
const isBashMode = true
const inputValue = 'ls -la'
// The stored value should NOT have the '!' prefix
expect(inputValue).toBe('ls -la')
expect(inputValue).not.toContain('!')
})
test('normal mode input can contain "!" anywhere', () => {
const isBashMode = false
const inputValue = 'fix this bug!'
// In normal mode, '!' is just a regular character
expect(inputValue).toContain('!')
})
})
describe('bash mode submission', () => {
test('submitting bash command prepends "!" to the stored value', () => {
const isBashMode = true
const trimmedInput = 'ls -la' // The stored value WITHOUT '!'
// Router logic prepends '!' when in bash mode
const commandWithBang = '!' + trimmedInput
expect(commandWithBang).toBe('!ls -la')
})
test('submission displays "!" in user message', () => {
const isBashMode = true
const trimmedInput = 'pwd'
const commandWithBang = '!' + trimmedInput
// The user message should show the command WITH '!'
const userMessage = { content: commandWithBang }
expect(userMessage.content).toBe('!pwd')
})
test('submission saves command WITH "!" to history', () => {
const saveToHistory = mock((cmd: string) => {})
const isBashMode = true
const trimmedInput = 'git status'
const commandWithBang = '!' + trimmedInput
// History should save the full command with '!'
saveToHistory(commandWithBang)
expect(saveToHistory).toHaveBeenCalled()
})
test('submission exits bash mode after running command', () => {
const setBashMode = mock(() => {})
const isBashMode = true
// After submission, bash mode should be exited
setBashMode()
expect(setBashMode).toHaveBeenCalled()
})
test('terminal command receives value WITHOUT "!" prefix', () => {
const runTerminalCommand = mock((params: any) => Promise.resolve([{ value: { stdout: 'output' } }]))
const isBashMode = true
const trimmedInput = 'echo hello'
// The actual terminal command should NOT include the '!'
runTerminalCommand({
command: trimmedInput,
process_type: 'SYNC',
cwd: process.cwd(),
timeout_seconds: -1,
env: process.env,
})
expect(runTerminalCommand).toHaveBeenCalled()
})
})
describe('bash mode UI state', () => {
test('bash mode flag is stored separately from input value', () => {
// The isBashMode flag is independent of the input text
const state1 = { isBashMode: true, inputValue: 'ls' }
const state2 = { isBashMode: false, inputValue: 'hello' }
expect(state1.isBashMode).toBe(true)
expect(state1.inputValue).not.toContain('!')
expect(state2.isBashMode).toBe(false)
expect(state2.inputValue).not.toContain('!')
})
test('input width is adjusted in bash mode for "!" column', () => {
const baseInputWidth = 100
const isBashMode = true
// Width should be reduced by 2 to account for '!' and spacing
const adjustedInputWidth = isBashMode ? baseInputWidth - 2 : baseInputWidth
expect(adjustedInputWidth).toBe(98)
})
test('input width is NOT adjusted when not in bash mode', () => {
const baseInputWidth = 100
const isBashMode = false
const adjustedInputWidth = isBashMode ? baseInputWidth - 2 : baseInputWidth
expect(adjustedInputWidth).toBe(100)
})
test('placeholder changes in bash mode', () => {
const normalPlaceholder = 'Ask Buffy anything...'
const bashPlaceholder = 'enter bash command...'
const isBashMode = true
const effectivePlaceholder = isBashMode ? bashPlaceholder : normalPlaceholder
expect(effectivePlaceholder).toBe('enter bash command...')
})
test('placeholder is normal when not in bash mode', () => {
const normalPlaceholder = 'Ask Buffy anything...'
const bashPlaceholder = 'enter bash command...'
const isBashMode = false
const effectivePlaceholder = isBashMode ? bashPlaceholder : normalPlaceholder
expect(effectivePlaceholder).toBe('Ask Buffy anything...')
})
})
describe('edge cases', () => {
test('empty string is NOT the same as "!"', () => {
const isBashMode = false
const inputValue: string = ''
const exclamation = '!'
const inputEqualsExclamation = inputValue === exclamation
expect(inputEqualsExclamation).toBe(false)
})
test('whitespace around "!" prevents bash mode entry', () => {
const isBashMode = false
const exclamation = '!'
const inputValue1: string = ' !'
const inputValue2: string = '! '
const inputValue3: string = ' ! '
const match1 = inputValue1 === exclamation
const match2 = inputValue2 === exclamation
const match3 = inputValue3 === exclamation
expect(match1).toBe(false)
expect(match2).toBe(false)
expect(match3).toBe(false)
})
test('multiple "!" characters do not enter bash mode', () => {
const isBashMode = false
const inputValue: string = '!!'
const exclamation = '!'
const inputEqualsExclamation = inputValue === exclamation
expect(inputEqualsExclamation).toBe(false)
})
test('bash mode can be entered, exited, and re-entered', () => {
let isBashMode = false
const exclamation = '!'
const empty = ''
// Enter bash mode
if (exclamation === exclamation) {
isBashMode = true
}
expect(isBashMode).toBe(true)
// Exit bash mode
if (isBashMode && empty === empty) {
isBashMode = false
}
expect(isBashMode).toBe(false)
// Re-enter bash mode
if (!isBashMode && exclamation === exclamation) {
isBashMode = true
}
expect(isBashMode).toBe(true)
})
})
describe('integration with command router', () => {
test('bash mode commands are routed differently than normal prompts', () => {
const isBashMode = true
const normalPrompt = false
// In bash mode, commands should be handled by terminal execution
// Not by the LLM agent
expect(isBashMode).toBe(true)
expect(normalPrompt).toBe(false)
})
test('normal commands starting with "!" are NOT bash commands', () => {
const isBashMode = false
const inputValue = '!ls' // User typed this in normal mode
// This should be treated as a normal prompt, not a bash command
// because bash mode was not activated
expect(isBashMode).toBe(false)
})
test('bash mode takes precedence over slash commands', () => {
const isBashMode = true
const trimmedInput = '/help' // Looks like a slash command
// But in bash mode, it's just a bash command
if (isBashMode) {
const commandWithBang = '!' + trimmedInput
expect(commandWithBang).toBe('!/help')
}
})
})
})