Skip to content

Commit 83a14dd

Browse files
committed
/review!
1 parent 6365f88 commit 83a14dd

File tree

5 files changed

+391
-59
lines changed

5 files changed

+391
-59
lines changed

cli/src/chat.tsx

Lines changed: 99 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { AdBanner } from './components/ad-banner'
1616
import { BottomStatusLine } from './components/bottom-status-line'
1717
import { ChatInputBar } from './components/chat-input-bar'
1818
import { LoadPreviousButton } from './components/load-previous-button'
19+
import { ReviewScreen } from './components/review-screen'
1920
import { MessageWithAgents } from './components/message-with-agents'
2021
import { areCreditsRestored } from './components/out-of-credits-banner'
2122
import { PendingBashMessage } from './components/pending-bash-message'
@@ -46,6 +47,7 @@ import { WEBSITE_URL } from './login/constants'
4647
import { getProjectRoot } from './project-files'
4748
import { useChatHistoryStore } from './state/chat-history-store'
4849
import { useChatStore } from './state/chat-store'
50+
import { useReviewStore } from './state/review-store'
4951
import { useFeedbackStore } from './state/feedback-store'
5052
import { useMessageBlockStore } from './state/message-block-store'
5153
import { usePublishStore } from './state/publish-store'
@@ -633,6 +635,13 @@ export const Chat = ({
633635
})),
634636
)
635637

638+
const { reviewMode, closeReviewScreen } = useReviewStore(
639+
useShallow((state) => ({
640+
reviewMode: state.reviewMode,
641+
closeReviewScreen: state.closeReviewScreen,
642+
})),
643+
)
644+
636645
const publishMutation = usePublishMutation()
637646

638647
const handleCommandResult = useCallback(
@@ -664,6 +673,10 @@ export const Chat = ({
664673
if (result.openChatHistory) {
665674
useChatHistoryStore.getState().openChatHistory()
666675
}
676+
677+
if (result.openReviewScreen) {
678+
useReviewStore.getState().openReviewScreen()
679+
}
667680
},
668681
[
669682
saveCurrentInput,
@@ -790,6 +803,26 @@ export const Chat = ({
790803
setInputFocused(true)
791804
}, [closePublish, setInputFocused])
792805

806+
const handleReviewOptionSelect = useCallback(
807+
(reviewText: string) => {
808+
closeReviewScreen()
809+
setInputFocused(true)
810+
// Submit the review request
811+
onSubmitPrompt(reviewText, agentMode)
812+
.then((result) => handleCommandResult(result))
813+
.catch((error) => {
814+
logger.error({ error }, '[review] Failed to submit review prompt')
815+
showClipboardMessage('Failed to send review request', { durationMs: 3000 })
816+
})
817+
},
818+
[closeReviewScreen, setInputFocused, onSubmitPrompt, agentMode, handleCommandResult],
819+
)
820+
821+
const handleCloseReviewScreen = useCallback(() => {
822+
closeReviewScreen()
823+
setInputFocused(true)
824+
}, [closeReviewScreen, setInputFocused])
825+
793826
const handlePublish = useCallback(
794827
async (agentIds: string[]) => {
795828
await publishMutation.mutateAsync(agentIds)
@@ -1142,7 +1175,7 @@ export const Chat = ({
11421175
useChatKeyboard({
11431176
state: chatKeyboardState,
11441177
handlers: chatKeyboardHandlers,
1145-
disabled: askUserState !== null,
1178+
disabled: askUserState !== null || reviewMode,
11461179
})
11471180

11481181
// Sync message block context to zustand store for child components
@@ -1373,64 +1406,71 @@ export const Chat = ({
13731406

13741407
{ad && getAdsEnabled() && <AdBanner ad={ad} />}
13751408

1376-
<ChatInputBar
1377-
inputValue={inputValue}
1378-
cursorPosition={cursorPosition}
1379-
setInputValue={setInputValue}
1380-
inputFocused={inputFocused}
1381-
inputRef={inputRef}
1382-
inputPlaceholder={inputPlaceholder}
1383-
lastEditDueToNav={lastEditDueToNav}
1384-
agentMode={agentMode}
1385-
toggleAgentMode={toggleAgentMode}
1386-
setAgentMode={setAgentMode}
1387-
hasSlashSuggestions={hasSlashSuggestions}
1388-
hasMentionSuggestions={hasMentionSuggestions}
1389-
hasSuggestionMenu={hasSuggestionMenu}
1390-
slashSuggestionItems={slashSuggestionItems}
1391-
agentSuggestionItems={agentSuggestionItems}
1392-
fileSuggestionItems={fileSuggestionItems}
1393-
slashSelectedIndex={slashSelectedIndex}
1394-
agentSelectedIndex={agentSelectedIndex}
1395-
onSlashItemClick={handleSlashItemClick}
1396-
onMentionItemClick={handleMentionItemClick}
1397-
theme={theme}
1398-
terminalHeight={terminalHeight}
1399-
separatorWidth={separatorWidth}
1400-
shouldCenterInputVertically={shouldCenterInputVertically}
1401-
inputBoxTitle={inputBoxTitle}
1402-
isCompactHeight={isCompactHeight}
1403-
isNarrowWidth={isNarrowWidth}
1404-
feedbackMode={feedbackMode}
1405-
handleExitFeedback={handleExitFeedback}
1406-
publishMode={publishMode}
1407-
handleExitPublish={handleExitPublish}
1408-
handlePublish={handlePublish}
1409-
handleSubmit={handleSubmit}
1410-
onPaste={createPasteHandler({
1411-
text: inputValue,
1412-
cursorPosition,
1413-
onChange: setInputValue,
1414-
onPasteImage: chatKeyboardHandlers.onPasteImage,
1415-
onPasteImagePath: chatKeyboardHandlers.onPasteImagePath,
1416-
onPasteLongText: (pastedText) => {
1417-
const id = crypto.randomUUID()
1418-
const preview = pastedText.slice(0, 100).replace(/\n/g, ' ')
1419-
useChatStore.getState().addPendingTextAttachment({
1420-
id,
1421-
content: pastedText,
1422-
preview,
1423-
charCount: pastedText.length,
1424-
})
1425-
// Show temporary status message
1426-
showClipboardMessage(
1427-
`📋 Pasted text (${pastedText.length.toLocaleString()} chars)`,
1428-
{ durationMs: 5000 },
1429-
)
1430-
},
1431-
cwd: getProjectRoot() ?? process.cwd(),
1432-
})}
1433-
/>
1409+
{reviewMode ? (
1410+
<ReviewScreen
1411+
onSelectOption={handleReviewOptionSelect}
1412+
onCancel={handleCloseReviewScreen}
1413+
/>
1414+
) : (
1415+
<ChatInputBar
1416+
inputValue={inputValue}
1417+
cursorPosition={cursorPosition}
1418+
setInputValue={setInputValue}
1419+
inputFocused={inputFocused}
1420+
inputRef={inputRef}
1421+
inputPlaceholder={inputPlaceholder}
1422+
lastEditDueToNav={lastEditDueToNav}
1423+
agentMode={agentMode}
1424+
toggleAgentMode={toggleAgentMode}
1425+
setAgentMode={setAgentMode}
1426+
hasSlashSuggestions={hasSlashSuggestions}
1427+
hasMentionSuggestions={hasMentionSuggestions}
1428+
hasSuggestionMenu={hasSuggestionMenu}
1429+
slashSuggestionItems={slashSuggestionItems}
1430+
agentSuggestionItems={agentSuggestionItems}
1431+
fileSuggestionItems={fileSuggestionItems}
1432+
slashSelectedIndex={slashSelectedIndex}
1433+
agentSelectedIndex={agentSelectedIndex}
1434+
onSlashItemClick={handleSlashItemClick}
1435+
onMentionItemClick={handleMentionItemClick}
1436+
theme={theme}
1437+
terminalHeight={terminalHeight}
1438+
separatorWidth={separatorWidth}
1439+
shouldCenterInputVertically={shouldCenterInputVertically}
1440+
inputBoxTitle={inputBoxTitle}
1441+
isCompactHeight={isCompactHeight}
1442+
isNarrowWidth={isNarrowWidth}
1443+
feedbackMode={feedbackMode}
1444+
handleExitFeedback={handleExitFeedback}
1445+
publishMode={publishMode}
1446+
handleExitPublish={handleExitPublish}
1447+
handlePublish={handlePublish}
1448+
handleSubmit={handleSubmit}
1449+
onPaste={createPasteHandler({
1450+
text: inputValue,
1451+
cursorPosition,
1452+
onChange: setInputValue,
1453+
onPasteImage: chatKeyboardHandlers.onPasteImage,
1454+
onPasteImagePath: chatKeyboardHandlers.onPasteImagePath,
1455+
onPasteLongText: (pastedText) => {
1456+
const id = crypto.randomUUID()
1457+
const preview = pastedText.slice(0, 100).replace(/\n/g, ' ')
1458+
useChatStore.getState().addPendingTextAttachment({
1459+
id,
1460+
content: pastedText,
1461+
preview,
1462+
charCount: pastedText.length,
1463+
})
1464+
// Show temporary status message
1465+
showClipboardMessage(
1466+
`📋 Pasted text (${pastedText.length.toLocaleString()} chars)`,
1467+
{ durationMs: 5000 },
1468+
)
1469+
},
1470+
cwd: getProjectRoot() ?? process.cwd(),
1471+
})}
1472+
/>
1473+
)}
14341474

14351475
<BottomStatusLine
14361476
isClaudeConnected={isClaudeOAuthActive}

cli/src/commands/command-registry.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export type CommandResult = {
5656
openFeedbackMode?: boolean
5757
openPublishMode?: boolean
5858
openChatHistory?: boolean
59+
openReviewScreen?: boolean
5960
preSelectAgents?: string[]
6061
} | void
6162

@@ -487,6 +488,31 @@ export const COMMAND_REGISTRY: CommandDefinition[] = [
487488
return { openChatHistory: true }
488489
},
489490
}),
491+
defineCommandWithArgs({
492+
name: 'review',
493+
handler: (params, args) => {
494+
const trimmedArgs = args.trim()
495+
496+
params.saveToHistory(params.inputValue.trim())
497+
clearInput(params)
498+
499+
// If user provided review text directly, send it immediately without showing the screen
500+
if (trimmedArgs) {
501+
const reviewPrompt = `@GPT-5 Agent Please review: ${trimmedArgs}`
502+
params.sendMessage({
503+
content: reviewPrompt,
504+
agentMode: params.agentMode,
505+
})
506+
setTimeout(() => {
507+
params.scrollToLatest()
508+
}, 0)
509+
return
510+
}
511+
512+
// Otherwise open the selection UI
513+
return { openReviewScreen: true }
514+
},
515+
}),
490516
]
491517

492518
export function findCommand(cmd: string): CommandDefinition | undefined {

0 commit comments

Comments
 (0)