rebrand better-clawd and ship initial npm-ready release
This commit is contained in:
@@ -292,6 +292,8 @@ import { createAttachmentMessage, getQueuedCommandAttachments } from '../utils/a
|
||||
// creating a new [] literal on every render in remote mode, which would
|
||||
// cause useEffect dependency changes and infinite re-render loops.
|
||||
const EMPTY_MCP_CLIENTS: MCPServerConnection[] = [];
|
||||
const EMPTY_TOOL_USE_CONFIRM_QUEUE: ToolUseConfirm[] = [];
|
||||
const EMPTY_IN_PROGRESS_TOOL_USE_IDS = new Set<string>();
|
||||
|
||||
// Stable stub for useAssistantHistory's non-KAIROS branch — avoids a new
|
||||
// function identity each render, which would break composedOnScroll's memo.
|
||||
@@ -980,6 +982,14 @@ export function REPL({
|
||||
// True when user is actively typing — defers interrupt dialogs so keystrokes
|
||||
// don't accidentally dismiss or answer a permission prompt the user hasn't read yet.
|
||||
const [isPromptInputActive, setIsPromptInputActive] = React.useState(false);
|
||||
const promptInputActiveRef = useRef(false);
|
||||
const setPromptInputActive = useCallback((active: boolean) => {
|
||||
if (promptInputActiveRef.current === active) {
|
||||
return;
|
||||
}
|
||||
promptInputActiveRef.current = active;
|
||||
setIsPromptInputActive(active);
|
||||
}, []);
|
||||
const [autoUpdaterResult, setAutoUpdaterResult] = useState<AutoUpdaterResult | null>(null);
|
||||
useEffect(() => {
|
||||
if (autoUpdaterResult?.notifications) {
|
||||
@@ -1359,16 +1369,16 @@ export function REPL({
|
||||
// block's `=== ''` guard — see the fresh value, not the stale render.
|
||||
inputValueRef.current = value;
|
||||
setInputValueRaw(value);
|
||||
setIsPromptInputActive(value.trim().length > 0);
|
||||
}, [setIsPromptInputActive, repinScroll, trySuggestBgPRIntercept]);
|
||||
setPromptInputActive(value.trim().length > 0);
|
||||
}, [setPromptInputActive, repinScroll, trySuggestBgPRIntercept]);
|
||||
|
||||
// Schedule a timeout to stop suppressing dialogs after the user stops typing.
|
||||
// Only manages the timeout — the immediate activation is handled by setInputValue above.
|
||||
useEffect(() => {
|
||||
if (inputValue.trim().length === 0) return;
|
||||
const timer = setTimeout(setIsPromptInputActive, PROMPT_SUPPRESSION_MS, false);
|
||||
const timer = setTimeout(setPromptInputActive, PROMPT_SUPPRESSION_MS, false);
|
||||
return () => clearTimeout(timer);
|
||||
}, [inputValue]);
|
||||
}, [inputValue, setPromptInputActive]);
|
||||
const [inputMode, setInputMode] = useState<PromptInputMode>('prompt');
|
||||
const [stashedPrompt, setStashedPrompt] = useState<{
|
||||
text: string;
|
||||
@@ -4399,7 +4409,7 @@ export function REPL({
|
||||
// and transcript-mode are mutually exclusive (this early return), so
|
||||
// only one ScrollBox is ever mounted at a time.
|
||||
const transcriptScrollRef = isFullscreenEnvEnabled() && !disableVirtualScroll && !dumpMode ? scrollRef : undefined;
|
||||
const transcriptMessagesElement = <Messages messages={transcriptMessages} tools={tools} commands={commands} verbose={true} toolJSX={null} toolUseConfirmQueue={[]} inProgressToolUseIDs={inProgressToolUseIDs} isMessageSelectorVisible={false} conversationId={conversationId} screen={screen} agentDefinitions={agentDefinitions} streamingToolUses={transcriptStreamingToolUses} showAllInTranscript={showAllInTranscript} onOpenRateLimitOptions={handleOpenRateLimitOptions} isLoading={isLoading} hidePastThinking={true} streamingThinking={streamingThinking} scrollRef={transcriptScrollRef} jumpRef={jumpRef} onSearchMatchesChange={onSearchMatchesChange} scanElement={scanElement} setPositions={setPositions} disableRenderCap={dumpMode} />;
|
||||
const transcriptMessagesElement = <Messages messages={transcriptMessages} tools={tools} commands={commands} verbose={true} toolJSX={null} toolUseConfirmQueue={EMPTY_TOOL_USE_CONFIRM_QUEUE} inProgressToolUseIDs={inProgressToolUseIDs} isMessageSelectorVisible={false} conversationId={conversationId} screen={screen} agentDefinitions={agentDefinitions} streamingToolUses={transcriptStreamingToolUses} showAllInTranscript={showAllInTranscript} onOpenRateLimitOptions={handleOpenRateLimitOptions} isLoading={isLoading} hidePastThinking={true} streamingThinking={streamingThinking} scrollRef={transcriptScrollRef} jumpRef={jumpRef} onSearchMatchesChange={onSearchMatchesChange} scanElement={scanElement} setPositions={setPositions} disableRenderCap={dumpMode} />;
|
||||
const transcriptToolJSX = toolJSX && <Box flexDirection="column" width="100%">
|
||||
{toolJSX.jsx}
|
||||
</Box>;
|
||||
@@ -4507,6 +4517,7 @@ export function REPL({
|
||||
// When viewing an agent, never fall through to leader — empty until
|
||||
// bootstrap/stream fills. Closes the see-leader-type-agent footgun.
|
||||
const displayedMessages = viewedAgentTask ? viewedAgentTask.messages ?? [] : usesSyncMessages ? messages : deferredMessages;
|
||||
const activeInProgressToolUseIDs = viewedTeammateTask ? viewedTeammateTask.inProgressToolUseIDs ?? EMPTY_IN_PROGRESS_TOOL_USE_IDS : inProgressToolUseIDs;
|
||||
// Show the placeholder until the real user message appears in
|
||||
// displayedMessages. userInputOnProcessing stays set for the whole turn
|
||||
// (cleared in resetLoadingState); this length check hides it once
|
||||
@@ -4567,7 +4578,7 @@ export function REPL({
|
||||
jumpToNew(scrollRef.current);
|
||||
}} scrollable={<>
|
||||
<TeammateViewHeader />
|
||||
<Messages messages={displayedMessages} tools={tools} commands={commands} verbose={verbose} toolJSX={toolJSX} toolUseConfirmQueue={toolUseConfirmQueue} inProgressToolUseIDs={viewedTeammateTask ? viewedTeammateTask.inProgressToolUseIDs ?? new Set() : inProgressToolUseIDs} isMessageSelectorVisible={isMessageSelectorVisible} conversationId={conversationId} screen={screen} streamingToolUses={streamingToolUses} showAllInTranscript={showAllInTranscript} agentDefinitions={agentDefinitions} onOpenRateLimitOptions={handleOpenRateLimitOptions} isLoading={isLoading} streamingText={isLoading && !viewedAgentTask ? visibleStreamingText : null} isBriefOnly={viewedAgentTask ? false : isBriefOnly} unseenDivider={viewedAgentTask ? undefined : unseenDivider} scrollRef={isFullscreenEnvEnabled() ? scrollRef : undefined} trackStickyPrompt={isFullscreenEnvEnabled() ? true : undefined} cursor={cursor} setCursor={setCursor} cursorNavRef={cursorNavRef} />
|
||||
<Messages messages={displayedMessages} tools={tools} commands={commands} verbose={verbose} toolJSX={toolJSX} toolUseConfirmQueue={toolUseConfirmQueue} inProgressToolUseIDs={activeInProgressToolUseIDs} isMessageSelectorVisible={isMessageSelectorVisible} conversationId={conversationId} screen={screen} streamingToolUses={streamingToolUses} showAllInTranscript={showAllInTranscript} agentDefinitions={agentDefinitions} onOpenRateLimitOptions={handleOpenRateLimitOptions} isLoading={isLoading} streamingText={isLoading && !viewedAgentTask ? visibleStreamingText : null} isBriefOnly={viewedAgentTask ? false : isBriefOnly} unseenDivider={viewedAgentTask ? undefined : unseenDivider} scrollRef={isFullscreenEnvEnabled() ? scrollRef : undefined} trackStickyPrompt={isFullscreenEnvEnabled() ? true : undefined} cursor={cursor} setCursor={setCursor} cursorNavRef={cursorNavRef} />
|
||||
<AwsAuthStatusBox />
|
||||
{/* Hide the processing placeholder while a modal is showing —
|
||||
it would sit at the last visible transcript row right above
|
||||
|
||||
Reference in New Issue
Block a user