wave-code 0.19.9 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +20 -1
- package/dist/components/App.js +7 -0
- package/dist/components/BtwDisplay.js +13 -3
- package/dist/components/ChatInterface.js +21 -6
- package/dist/components/HelpView.js +6 -0
- package/dist/components/InputBox.d.ts +1 -2
- package/dist/components/InputBox.js +16 -5
- package/dist/components/LoadingIndicator.d.ts +1 -2
- package/dist/components/LoadingIndicator.js +2 -2
- package/dist/components/Markdown.js +13 -16
- package/dist/components/MessageList.d.ts +2 -1
- package/dist/components/MessageList.js +2 -2
- package/dist/components/RewindCommand.js +4 -2
- package/dist/components/StatusLine.d.ts +0 -2
- package/dist/components/StatusLine.js +6 -6
- package/dist/components/TaskList.js +2 -1
- package/dist/components/ToolDisplay.d.ts +1 -0
- package/dist/components/ToolDisplay.js +17 -9
- package/dist/constants/commands.js +0 -6
- package/dist/contexts/useChat.d.ts +3 -5
- package/dist/contexts/useChat.js +242 -82
- package/dist/daemon-cli.d.ts +10 -0
- package/dist/daemon-cli.js +15 -0
- package/dist/hooks/useInputManager.d.ts +1 -0
- package/dist/hooks/useInputManager.js +120 -40
- package/dist/index.js +10 -0
- package/dist/managers/inputHandlers.js +55 -30
- package/dist/managers/inputReducer.d.ts +22 -22
- package/dist/managers/inputReducer.js +361 -177
- package/dist/print-cli.js +36 -10
- package/dist/stdio/agentBridge.d.ts +23 -0
- package/dist/stdio/agentBridge.js +151 -18
- package/dist/stdio/daemonServer.d.ts +67 -0
- package/dist/stdio/daemonServer.js +191 -0
- package/dist/stdio/index.d.ts +2 -0
- package/dist/stdio/index.js +2 -0
- package/dist/stdio/jsonRpcConnection.d.ts +30 -0
- package/dist/stdio/jsonRpcConnection.js +127 -0
- package/dist/stdio/protocol.d.ts +2 -2
- package/dist/stdio/stdioServer.d.ts +2 -7
- package/dist/stdio/stdioServer.js +9 -100
- package/dist/utils/bracketedPaste.d.ts +39 -0
- package/dist/utils/bracketedPaste.js +122 -0
- package/dist/utils/markdownTable.d.ts +34 -0
- package/dist/utils/markdownTable.js +302 -0
- package/dist/utils/rewindCheckpoints.d.ts +8 -0
- package/dist/utils/rewindCheckpoints.js +15 -0
- package/dist/utils/throttle.d.ts +3 -3
- package/dist/utils/worktree.d.ts +8 -0
- package/dist/utils/worktree.js +32 -1
- package/package.json +4 -2
- package/src/cli.tsx +20 -1
- package/src/components/App.tsx +5 -0
- package/src/components/BtwDisplay.tsx +36 -12
- package/src/components/ChatInterface.tsx +26 -11
- package/src/components/HelpView.tsx +6 -0
- package/src/components/InputBox.tsx +21 -10
- package/src/components/LoadingIndicator.tsx +1 -4
- package/src/components/Markdown.tsx +15 -18
- package/src/components/MessageList.tsx +6 -0
- package/src/components/RewindCommand.tsx +4 -2
- package/src/components/StatusLine.tsx +0 -10
- package/src/components/TaskList.tsx +2 -1
- package/src/components/ToolDisplay.tsx +17 -6
- package/src/constants/commands.ts +0 -6
- package/src/contexts/useChat.tsx +310 -95
- package/src/daemon-cli.ts +17 -0
- package/src/hooks/useInputManager.ts +135 -43
- package/src/index.ts +12 -0
- package/src/managers/inputHandlers.ts +55 -32
- package/src/managers/inputReducer.ts +442 -214
- package/src/print-cli.ts +48 -11
- package/src/stdio/agentBridge.ts +213 -18
- package/src/stdio/daemonServer.ts +212 -0
- package/src/stdio/index.ts +2 -0
- package/src/stdio/jsonRpcConnection.ts +160 -0
- package/src/stdio/protocol.ts +5 -2
- package/src/stdio/stdioServer.ts +14 -120
- package/src/utils/bracketedPaste.ts +170 -0
- package/src/utils/markdownTable.ts +359 -0
- package/src/utils/rewindCheckpoints.ts +15 -0
- package/src/utils/throttle.ts +8 -8
- package/src/utils/worktree.ts +50 -1
package/dist/cli.js
CHANGED
|
@@ -7,6 +7,16 @@ export async function startCli(options) {
|
|
|
7
7
|
const { restoreSessionId, continueLastSession, bypassPermissions, permissionMode, pluginDirs, tools, allowedTools, disallowedTools, worktreeSession, workdir, originalCwd, version, model, mcpServers, } = options;
|
|
8
8
|
// Continue with ink-based UI for normal mode
|
|
9
9
|
let shouldRemoveWorktree = false;
|
|
10
|
+
// Enable bracketed paste (DECSET 2004) so terminals wrap pasted text in
|
|
11
|
+
// \x1b[200~ ... \x1b[201~ markers. The input pipeline uses these to insert
|
|
12
|
+
// pasted text without submitting (a pasted trailing \r is not an Enter).
|
|
13
|
+
// Terminals without bracketed-paste support ignore the sequence and paste
|
|
14
|
+
// without markers, falling back to legacy behavior. No-op when stdout is
|
|
15
|
+
// not a TTY (piped input, stdio mode).
|
|
16
|
+
const stdoutIsTTY = process.stdout.isTTY === true;
|
|
17
|
+
if (stdoutIsTTY) {
|
|
18
|
+
process.stdout.write("\x1b[?2004h");
|
|
19
|
+
}
|
|
10
20
|
const handleExit = (shouldRemove) => {
|
|
11
21
|
shouldRemoveWorktree = shouldRemove;
|
|
12
22
|
unmount();
|
|
@@ -14,7 +24,16 @@ export async function startCli(options) {
|
|
|
14
24
|
// Render the application
|
|
15
25
|
const { unmount, waitUntilExit } = render(_jsx(App, { restoreSessionId: restoreSessionId, continueLastSession: continueLastSession, bypassPermissions: bypassPermissions, permissionMode: permissionMode, pluginDirs: pluginDirs, tools: tools, allowedTools: allowedTools, disallowedTools: disallowedTools, worktreeSession: worktreeSession, workdir: workdir, originalCwd: originalCwd, version: version, model: model, mcpServers: mcpServers, onExit: handleExit }), { exitOnCtrlC: false });
|
|
16
26
|
// Wait for the app to finish unmounting
|
|
17
|
-
|
|
27
|
+
try {
|
|
28
|
+
await waitUntilExit();
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
// Disable bracketed paste (DECSET 2004) so the terminal returns to its
|
|
32
|
+
// previous paste handling.
|
|
33
|
+
if (stdoutIsTTY) {
|
|
34
|
+
process.stdout.write("\x1b[?2004l");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
18
37
|
try {
|
|
19
38
|
// Clean up old log files
|
|
20
39
|
await cleanupLogs().catch((error) => {
|
package/dist/components/App.js
CHANGED
|
@@ -6,6 +6,7 @@ import { ChatProvider, useChat } from "../contexts/useChat.js";
|
|
|
6
6
|
import { AppProvider } from "../contexts/useAppConfig.js";
|
|
7
7
|
import { WorktreeExitPrompt } from "./WorktreeExitPrompt.js";
|
|
8
8
|
import { hasUncommittedChanges, hasNewCommits, getDefaultRemoteBranch, } from "wave-agent-sdk";
|
|
9
|
+
import { btwOverlayActiveRef } from "../managers/inputReducer.js";
|
|
9
10
|
/** Wraps ChatInterface with worktree exit handling, using useChat() for hook access. */
|
|
10
11
|
const ChatWithExitPrompt = ({ worktreeSession, onExit }) => {
|
|
11
12
|
const { triggerWorktreeRemoveHook } = useChat();
|
|
@@ -28,6 +29,9 @@ const ChatWithExitPrompt = ({ worktreeSession, onExit }) => {
|
|
|
28
29
|
}
|
|
29
30
|
}, [worktreeSession, onExit]);
|
|
30
31
|
useInput((input, key) => {
|
|
32
|
+
// While the /btw overlay is up it owns the keys; Ctrl+C must not quit
|
|
33
|
+
if (btwOverlayActiveRef.current)
|
|
34
|
+
return;
|
|
31
35
|
if (input === "c" && key.ctrl) {
|
|
32
36
|
handleSignal();
|
|
33
37
|
}
|
|
@@ -54,6 +58,9 @@ const AppWithProviders = ({ bypassPermissions, permissionMode, pluginDirs, tools
|
|
|
54
58
|
// Handle Ctrl-C for non-worktree sessions (immediate exit)
|
|
55
59
|
// Ink runs terminal in raw mode, so Ctrl+C arrives as useInput event, not SIGINT
|
|
56
60
|
useInput((input, key) => {
|
|
61
|
+
// While the /btw overlay is up it owns the keys; Ctrl+C must not quit
|
|
62
|
+
if (btwOverlayActiveRef.current)
|
|
63
|
+
return;
|
|
57
64
|
if (!worktreeSession && input === "c" && key.ctrl) {
|
|
58
65
|
onExit(false);
|
|
59
66
|
return true;
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { Markdown } from "./Markdown.js";
|
|
4
4
|
export const BtwDisplay = ({ btwState }) => {
|
|
5
|
-
|
|
5
|
+
// Rendered for a real question (loading or answered) and for the bare
|
|
6
|
+
// `/btw` usage message (question === "", answer set).
|
|
7
|
+
if (!btwState.question && !btwState.answer) {
|
|
6
8
|
return null;
|
|
7
9
|
}
|
|
8
|
-
|
|
10
|
+
const answer = btwState.answer ?? "";
|
|
11
|
+
// The SDK surfaces failure as the answer string; classify by prefix so it
|
|
12
|
+
// renders in error color (aligned with Claude Code's error display).
|
|
13
|
+
const isError = !btwState.isLoading &&
|
|
14
|
+
(answer.startsWith("(API error") ||
|
|
15
|
+
answer.startsWith("(The model tried to call") ||
|
|
16
|
+
answer === "No response received");
|
|
17
|
+
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [btwState.question && (_jsxs(Box, { children: [_jsxs(Text, { color: "warning", bold: true, children: ["/btw", " "] }), _jsx(Text, { dimColor: true, children: btwState.question })] })), _jsx(Box, { marginTop: 1, flexDirection: "column", children: btwState.isLoading ? (_jsx(Text, { color: "gray", children: "\u273B Answering..." })) : isError ? (_jsx(Text, { color: "error", children: answer })) : (_jsx(Markdown, { children: answer })) }), btwState.question && btwState.answer && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Escape to dismiss" }) })), !btwState.question && btwState.answer && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Escape to dismiss" }) }))] }));
|
|
9
18
|
};
|
|
19
|
+
BtwDisplay.displayName = "BtwDisplay";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useRef, useEffect } from "react";
|
|
2
|
+
import { useState, useRef, useEffect, useCallback } from "react";
|
|
3
3
|
import { Box, useStdout, measureElement, Static } from "ink";
|
|
4
|
+
import { authService } from "wave-agent-sdk";
|
|
4
5
|
import { MessageList } from "./MessageList.js";
|
|
5
6
|
import { InputBox } from "./InputBox.js";
|
|
6
7
|
import { LoadingIndicator } from "./LoadingIndicator.js";
|
|
@@ -10,12 +11,29 @@ import { ConfirmationDetails } from "./ConfirmationDetails.js";
|
|
|
10
11
|
import { ConfirmationSelector } from "./ConfirmationSelector.js";
|
|
11
12
|
import { useChat } from "../contexts/useChat.js";
|
|
12
13
|
export const ChatInterface = () => {
|
|
13
|
-
const { messages, isLoading, isCommandRunning, isCompacting, sendMessage, abortMessage, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, sessionId, latestTotalTokens, maxInputTokens, slashCommands, hasSlashCommand, isConfirmationVisible, hasPendingConfirmations, confirmingTool, handleConfirmationDecision, handleConfirmationCancel, version, workdir, remountKey, requestRemount,
|
|
14
|
+
const { messages, isLoading, isCommandRunning, isCompacting, sendMessage, abortMessage, mcpServers, connectMcpServer, disconnectMcpServer, isExpanded, sessionId, latestTotalTokens, maxInputTokens, slashCommands, hasSlashCommand, isConfirmationVisible, hasPendingConfirmations, confirmingTool, handleConfirmationDecision, handleConfirmationCancel, version, workdir, remountKey, requestRemount, getGatewayConfig, } = useChat();
|
|
14
15
|
const displayMessages = messages;
|
|
15
16
|
const [forceStatic, setForceStatic] = useState(false);
|
|
16
17
|
const { stdout } = useStdout();
|
|
17
18
|
const terminalHeight = stdout?.rows ?? 24;
|
|
18
19
|
const chatInterfaceRef = useRef(null);
|
|
20
|
+
// Compute whether the user has any usable auth/direct-API config,
|
|
21
|
+
// so the welcome page can prompt /login when neither is present.
|
|
22
|
+
const computeAuthState = useCallback(() => {
|
|
23
|
+
if (authService.isSSOAuthenticated())
|
|
24
|
+
return true;
|
|
25
|
+
const gateway = getGatewayConfig();
|
|
26
|
+
return Boolean(gateway.apiKey || gateway.baseURL);
|
|
27
|
+
}, [getGatewayConfig]);
|
|
28
|
+
const [hasAuth, setHasAuth] = useState(computeAuthState);
|
|
29
|
+
// Keep the /login hint in sync with auth state changes (login/logout).
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const unsubscribe = authService.onAuthChange(() => {
|
|
32
|
+
setHasAuth(computeAuthState());
|
|
33
|
+
});
|
|
34
|
+
return unsubscribe;
|
|
35
|
+
}, [computeAuthState]);
|
|
36
|
+
const showLoginHint = !hasAuth;
|
|
19
37
|
// Handle forceStatic mode for overflow and request remount when exiting
|
|
20
38
|
useEffect(() => {
|
|
21
39
|
if (isConfirmationVisible && chatInterfaceRef.current) {
|
|
@@ -37,8 +55,5 @@ export const ChatInterface = () => {
|
|
|
37
55
|
]);
|
|
38
56
|
if (!sessionId)
|
|
39
57
|
return null;
|
|
40
|
-
return (_jsxs(Box, { ref: chatInterfaceRef, flexDirection: "column", children: [_jsx(MessageList, { messages: displayMessages, isExpanded: isExpanded, version: version, workdir: workdir, forceStatic: forceStatic }, remountKey), !isConfirmationVisible && !isExpanded && (_jsxs(_Fragment, { children: [(isLoading ||
|
|
41
|
-
isCommandRunning ||
|
|
42
|
-
isCompacting ||
|
|
43
|
-
isGoalEvaluating) && (_jsx(LoadingIndicator, { isLoading: isLoading, isCommandRunning: isCommandRunning, isCompacting: isCompacting, isGoalEvaluating: isGoalEvaluating, latestTotalTokens: latestTotalTokens })), _jsx(TaskList, {}), _jsx(QueuedMessageList, {}), _jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, sendMessage: sendMessage, abortMessage: abortMessage, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand, latestTotalTokens: latestTotalTokens, maxInputTokens: maxInputTokens, isGoalActive: isGoalActive, goalElapsed: goalElapsed })] })), isConfirmationVisible && (_jsxs(_Fragment, { children: [forceStatic ? (_jsx(Static, { items: [{ key: "confirmation-details" }], children: () => (_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, planContent: confirmingTool.planContent, isExpanded: isExpanded }, "confirmation-details")) })) : (_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, planContent: confirmingTool.planContent, isExpanded: isExpanded })), _jsx(ConfirmationSelector, { toolName: confirmingTool.name, toolInput: confirmingTool.input, suggestedPrefix: confirmingTool.suggestedPrefix, hidePersistentOption: confirmingTool.hidePersistentOption, isExpanded: isExpanded, onDecision: handleConfirmationDecision, onCancel: handleConfirmationCancel })] }))] }));
|
|
58
|
+
return (_jsxs(Box, { ref: chatInterfaceRef, flexDirection: "column", children: [_jsx(MessageList, { messages: displayMessages, isExpanded: isExpanded, version: version, workdir: workdir, forceStatic: forceStatic, showLoginHint: showLoginHint }, remountKey), !isConfirmationVisible && !isExpanded && (_jsxs(_Fragment, { children: [(isLoading || isCommandRunning || isCompacting) && (_jsx(LoadingIndicator, { isLoading: isLoading, isCommandRunning: isCommandRunning, isCompacting: isCompacting, latestTotalTokens: latestTotalTokens })), _jsx(TaskList, {}), _jsx(QueuedMessageList, {}), _jsx(InputBox, { isLoading: isLoading, isCommandRunning: isCommandRunning, isCompacting: isCompacting, sendMessage: sendMessage, abortMessage: abortMessage, mcpServers: mcpServers, connectMcpServer: connectMcpServer, disconnectMcpServer: disconnectMcpServer, slashCommands: slashCommands, hasSlashCommand: hasSlashCommand, latestTotalTokens: latestTotalTokens, maxInputTokens: maxInputTokens })] })), isConfirmationVisible && (_jsxs(_Fragment, { children: [forceStatic ? (_jsx(Static, { items: [{ key: "confirmation-details" }], children: () => (_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, planContent: confirmingTool.planContent, isExpanded: isExpanded }, "confirmation-details")) })) : (_jsx(ConfirmationDetails, { toolName: confirmingTool.name, toolInput: confirmingTool.input, planContent: confirmingTool.planContent, isExpanded: isExpanded })), _jsx(ConfirmationSelector, { toolName: confirmingTool.name, toolInput: confirmingTool.input, suggestedPrefix: confirmingTool.suggestedPrefix, hidePersistentOption: confirmingTool.hidePersistentOption, isExpanded: isExpanded, onDecision: handleConfirmationDecision, onCancel: handleConfirmationCancel })] }))] }));
|
|
44
59
|
};
|
|
@@ -47,11 +47,17 @@ export const HelpView = ({ onCancel, commands = [], }) => {
|
|
|
47
47
|
{ key: "Ctrl+B", description: "Background current task" },
|
|
48
48
|
{ key: "Ctrl+V", description: "Paste image" },
|
|
49
49
|
{ key: "Ctrl+J", description: "Newline" },
|
|
50
|
+
{ key: "Ctrl+A", description: "Cursor to line start" },
|
|
51
|
+
{ key: "Ctrl+E", description: "Cursor to line end" },
|
|
52
|
+
{ key: "Ctrl+U", description: "Delete to line start" },
|
|
53
|
+
{ key: "Ctrl+K", description: "Delete to line end" },
|
|
54
|
+
{ key: "Ctrl+W", description: "Delete word before cursor" },
|
|
50
55
|
{ key: "Shift+Tab", description: "Cycle permission mode" },
|
|
51
56
|
{
|
|
52
57
|
key: "Esc",
|
|
53
58
|
description: "Interrupt AI or command / Cancel selector / Close help",
|
|
54
59
|
},
|
|
60
|
+
{ key: "Esc ×2", description: "Clear input (idle)" },
|
|
55
61
|
];
|
|
56
62
|
const footerText = [
|
|
57
63
|
"Tab switch",
|
|
@@ -5,6 +5,7 @@ export declare const INPUT_PLACEHOLDER_TEXT_PREFIX: string;
|
|
|
5
5
|
export interface InputBoxProps {
|
|
6
6
|
isLoading?: boolean;
|
|
7
7
|
isCommandRunning?: boolean;
|
|
8
|
+
isCompacting?: boolean;
|
|
8
9
|
workdir?: string;
|
|
9
10
|
sendMessage?: (message: string, images?: Array<{
|
|
10
11
|
path: string;
|
|
@@ -18,7 +19,5 @@ export interface InputBoxProps {
|
|
|
18
19
|
hasSlashCommand?: (commandId: string) => boolean;
|
|
19
20
|
latestTotalTokens?: number;
|
|
20
21
|
maxInputTokens?: number;
|
|
21
|
-
isGoalActive?: boolean;
|
|
22
|
-
goalElapsed?: string;
|
|
23
22
|
}
|
|
24
23
|
export declare const InputBox: React.FC<InputBoxProps>;
|
|
@@ -20,11 +20,14 @@ import { useInputManager } from "../hooks/useInputManager.js";
|
|
|
20
20
|
import { useChat } from "../contexts/useChat.js";
|
|
21
21
|
export const INPUT_PLACEHOLDER_TEXT = "Type your message (use /help for more info)...";
|
|
22
22
|
export const INPUT_PLACEHOLDER_TEXT_PREFIX = INPUT_PLACEHOLDER_TEXT.substring(0, 10);
|
|
23
|
-
export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mcpServers = [], connectMcpServer = async () => false, disconnectMcpServer = async () => false, slashCommands = [], hasSlashCommand = () => false, latestTotalTokens = 0, maxInputTokens = 200000,
|
|
24
|
-
const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, handleRewindSelect, backgroundCurrentTask, messages, getFullMessageThread, sessionId, workingDirectory, askBtw, clearMessages, compact,
|
|
23
|
+
export const InputBox = ({ isLoading, isCommandRunning, isCompacting, sendMessage = () => { }, abortMessage = () => { }, mcpServers = [], connectMcpServer = async () => false, disconnectMcpServer = async () => false, slashCommands = [], hasSlashCommand = () => false, latestTotalTokens = 0, maxInputTokens = 200000, }) => {
|
|
24
|
+
const { permissionMode: chatPermissionMode, setPermissionMode: setChatPermissionMode, handleRewindSelect, backgroundCurrentTask, messages, getFullMessageThread, sessionId, workingDirectory, askBtw, clearMessages, compact, currentModel, configuredModels, setModel, recreateAgent, recallQueuedMessage, queuedMessages, setIsBtwActive, } = useChat();
|
|
25
25
|
// Ref to hold setInputText so queue callbacks can access it before useInputManager returns
|
|
26
26
|
const setInputTextRef = useRef(() => { });
|
|
27
27
|
const hasQueuedMessages = (queuedMessages?.length ?? 0) > 0;
|
|
28
|
+
// Idle means no AI work in flight. Esc double-press clear only applies when
|
|
29
|
+
// idle; while busy, Esc keeps its abort semantics.
|
|
30
|
+
const isIdle = !(isLoading || isCommandRunning || isCompacting);
|
|
28
31
|
const onRecallQueuedMessage = useCallback(() => {
|
|
29
32
|
const msg = recallQueuedMessage();
|
|
30
33
|
if (msg) {
|
|
@@ -46,6 +49,8 @@ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mc
|
|
|
46
49
|
permissionMode, setPermissionMode,
|
|
47
50
|
// BTW state
|
|
48
51
|
btwState,
|
|
52
|
+
// Esc double-press clear pending
|
|
53
|
+
escClearPending,
|
|
49
54
|
// Main handler
|
|
50
55
|
handleInput,
|
|
51
56
|
// Manager ready state
|
|
@@ -56,7 +61,6 @@ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mc
|
|
|
56
61
|
onAskBtw: askBtw,
|
|
57
62
|
onClearMessages: clearMessages,
|
|
58
63
|
onCompact: compact,
|
|
59
|
-
onGoalCommand: goalCommand,
|
|
60
64
|
onHasSlashCommand: hasSlashCommand,
|
|
61
65
|
onAbortMessage: abortMessage,
|
|
62
66
|
onBackgroundCurrentTask: backgroundCurrentTask,
|
|
@@ -65,12 +69,19 @@ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mc
|
|
|
65
69
|
workdir: workingDirectory,
|
|
66
70
|
getFullMessageThread,
|
|
67
71
|
hasQueuedMessages,
|
|
72
|
+
isIdle,
|
|
68
73
|
onRecallQueuedMessage,
|
|
69
74
|
});
|
|
70
75
|
// Keep setInputText ref updated for queue callbacks
|
|
71
76
|
useEffect(() => {
|
|
72
77
|
setInputTextRef.current = setInputText;
|
|
73
78
|
}, [setInputText]);
|
|
79
|
+
// Sync the btw overlay's visibility to ChatContext so siblings (TaskList)
|
|
80
|
+
// can hide while the side-question is on display (aligned with Claude Code,
|
|
81
|
+
// which suppresses the expanded task list while a local-jsx command shows).
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
setIsBtwActive(btwState.question !== "" || btwState.answer !== undefined);
|
|
84
|
+
}, [btwState.question, btwState.answer, setIsBtwActive]);
|
|
74
85
|
// Sync permission mode from useChat to InputManager
|
|
75
86
|
useEffect(() => {
|
|
76
87
|
setPermissionMode(chatPermissionMode);
|
|
@@ -137,7 +148,7 @@ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mc
|
|
|
137
148
|
if (showModelSelector) {
|
|
138
149
|
return (_jsx(ModelSelector, { onCancel: () => setShowModelSelector(false), currentModel: currentModel, configuredModels: configuredModels, onSelectModel: setModel }));
|
|
139
150
|
}
|
|
140
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(BtwDisplay, { btwState: btwState }), showFileSelector && (_jsx(FileSelector, { files: filteredFiles, searchQuery: searchQuery, isLoading: isFileSearching, onSelect: handleFileSelect, onCancel: handleCancelFileSelect })), showCommandSelector && (_jsx(CommandSelector, { searchQuery: commandSearchQuery, onSelect: handleCommandSelect, onInsert: handleCommandInsert, onCancel: handleCancelCommandSelect, commands: slashCommands })), showHistorySearch && (_jsx(HistorySearch, { searchQuery: historySearchQuery, onSelect: handleHistorySearchSelect, onCancel: handleCancelHistorySearch })), showBackgroundTaskManager && (_jsx(BackgroundTaskManager, { onCancel: () => setShowBackgroundTaskManager(false) })), showMcpManager && (_jsx(McpManager, { onCancel: () => setShowMcpManager(false), servers: mcpServers, onConnectServer: connectMcpServer, onDisconnectServer: disconnectMcpServer })), showWorkflowManager && (_jsx(WorkflowManager, { onCancel: () => setShowWorkflowManager(false) })), btwState.question
|
|
151
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(BtwDisplay, { btwState: btwState }), showFileSelector && (_jsx(FileSelector, { files: filteredFiles, searchQuery: searchQuery, isLoading: isFileSearching, onSelect: handleFileSelect, onCancel: handleCancelFileSelect })), showCommandSelector && (_jsx(CommandSelector, { searchQuery: commandSearchQuery, onSelect: handleCommandSelect, onInsert: handleCommandInsert, onCancel: handleCancelCommandSelect, commands: slashCommands })), showHistorySearch && (_jsx(HistorySearch, { searchQuery: historySearchQuery, onSelect: handleHistorySearchSelect, onCancel: handleCancelHistorySearch })), showBackgroundTaskManager && (_jsx(BackgroundTaskManager, { onCancel: () => setShowBackgroundTaskManager(false) })), showMcpManager && (_jsx(McpManager, { onCancel: () => setShowMcpManager(false), servers: mcpServers, onConnectServer: connectMcpServer, onDisconnectServer: disconnectMcpServer })), showWorkflowManager && (_jsx(WorkflowManager, { onCancel: () => setShowWorkflowManager(false) })), btwState.question || btwState.answer
|
|
141
152
|
? null
|
|
142
153
|
: showBackgroundTaskManager ||
|
|
143
154
|
showMcpManager ||
|
|
@@ -146,5 +157,5 @@ export const InputBox = ({ sendMessage = () => { }, abortMessage = () => { }, mc
|
|
|
146
157
|
showStatusCommand ||
|
|
147
158
|
showLoginCommand ||
|
|
148
159
|
showPluginManager ||
|
|
149
|
-
showWorkflowManager || (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { borderStyle: "single", borderColor: "gray", borderLeft: false, borderRight: false, children: _jsx(Text, { color: isPlaceholder ? "gray" : "white", children: shouldShowCursor ? (_jsxs(_Fragment, { children: [beforeCursor, _jsx(Text, { backgroundColor: "white", color: "black", children: atCursor }), afterCursor] })) : (displayText) }) }), _jsx(StatusLine, { permissionMode: permissionMode, isShellCommand: isShellCommand,
|
|
160
|
+
showWorkflowManager || (_jsxs(Box, { flexDirection: "column", children: [escClearPending && _jsx(Text, { color: "gray", children: "\u518D\u6B21\u6309 Esc \u6E05\u7A7A\u8F93\u5165" }), _jsx(Box, { borderStyle: "single", borderColor: "gray", borderLeft: false, borderRight: false, children: _jsx(Text, { color: isPlaceholder ? "gray" : "white", children: shouldShowCursor ? (_jsxs(_Fragment, { children: [beforeCursor, _jsx(Text, { backgroundColor: "white", color: "black", children: atCursor }), afterCursor] })) : (displayText) }) }), _jsx(StatusLine, { permissionMode: permissionMode, isShellCommand: isShellCommand, latestTotalTokens: latestTotalTokens, maxInputTokens: maxInputTokens })] }))] }));
|
|
150
161
|
};
|
|
@@ -2,10 +2,9 @@ export interface LoadingIndicatorProps {
|
|
|
2
2
|
isLoading?: boolean;
|
|
3
3
|
isCommandRunning?: boolean;
|
|
4
4
|
isCompacting?: boolean;
|
|
5
|
-
isGoalEvaluating?: boolean;
|
|
6
5
|
latestTotalTokens?: number;
|
|
7
6
|
}
|
|
8
7
|
export declare const LoadingIndicator: {
|
|
9
|
-
({ isLoading, isCommandRunning, isCompacting,
|
|
8
|
+
({ isLoading, isCommandRunning, isCompacting, latestTotalTokens, }: LoadingIndicatorProps): import("react/jsx-runtime").JSX.Element;
|
|
10
9
|
displayName: string;
|
|
11
10
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
-
export const LoadingIndicator = ({ isLoading = false, isCommandRunning = false, isCompacting = false,
|
|
4
|
-
return (_jsxs(Box, { flexDirection: "column", children: [isLoading && !isCompacting &&
|
|
3
|
+
export const LoadingIndicator = ({ isLoading = false, isCommandRunning = false, isCompacting = false, latestTotalTokens = 0, }) => {
|
|
4
|
+
return (_jsxs(Box, { flexDirection: "column", children: [isLoading && !isCompacting && (_jsxs(Box, { children: [_jsx(Text, { color: "yellow", children: "\u273B AI is thinking... " }), latestTotalTokens > 0 && (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "gray", dimColor: true, children: ["|", " "] }), _jsx(Text, { color: "blue", bold: true, children: latestTotalTokens.toLocaleString() }), _jsxs(Text, { color: "gray", dimColor: true, children: [" ", "tokens", " "] })] })), _jsxs(Text, { color: "gray", dimColor: true, children: ["|", " "] }), _jsx(Text, { color: "red", bold: true, children: "Esc" }), _jsxs(Text, { color: "gray", dimColor: true, children: [" ", "to abort"] })] })), isCommandRunning && _jsx(Text, { color: "blue", children: "\u273B Command is running..." }), isCompacting && (_jsx(Text, { color: "magenta", children: "\u273B Compacting message history..." }))] }));
|
|
5
5
|
};
|
|
6
6
|
LoadingIndicator.displayName = "LoadingIndicator";
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import React, { useMemo } from "react";
|
|
3
|
-
import { Box, Text } from "ink";
|
|
3
|
+
import { Box, Text, useStdout } from "ink";
|
|
4
4
|
import { Renderer, marked } from "marked";
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
import { highlightToAnsi } from "../utils/highlightUtils.js";
|
|
7
|
+
import { renderMarkdownTable } from "../utils/markdownTable.js";
|
|
7
8
|
const unescapeHtml = (html) => {
|
|
8
9
|
return html
|
|
9
10
|
.replace(/&/g, "&")
|
|
@@ -14,6 +15,10 @@ const unescapeHtml = (html) => {
|
|
|
14
15
|
.replace(/'/g, "'");
|
|
15
16
|
};
|
|
16
17
|
class AnsiRenderer extends Renderer {
|
|
18
|
+
constructor(columns) {
|
|
19
|
+
super();
|
|
20
|
+
this.columns = columns;
|
|
21
|
+
}
|
|
17
22
|
code({ text, lang }) {
|
|
18
23
|
const prefix = lang ? `\`\`\`${lang}` : "```";
|
|
19
24
|
const suffix = "```";
|
|
@@ -67,18 +72,8 @@ class AnsiRenderer extends Renderer {
|
|
|
67
72
|
return `\n${text}\n`;
|
|
68
73
|
}
|
|
69
74
|
table(token) {
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
.map((row) => row.map((cell) => this.tablecell(cell)).join("") + "\n")
|
|
73
|
-
.join("");
|
|
74
|
-
return `\n${header}\n${body}\n`;
|
|
75
|
-
}
|
|
76
|
-
tablerow({ text }) {
|
|
77
|
-
return text + "\n";
|
|
78
|
-
}
|
|
79
|
-
tablecell(token) {
|
|
80
|
-
const text = token.header ? chalk.bold(token.text) : token.text;
|
|
81
|
-
return text + " | ";
|
|
75
|
+
const table = renderMarkdownTable(token, this.columns, (tokens) => this.parser.parseInline(tokens));
|
|
76
|
+
return `\n${table}\n`;
|
|
82
77
|
}
|
|
83
78
|
strong({ tokens }) {
|
|
84
79
|
const text = this.parser.parseInline(tokens);
|
|
@@ -114,16 +109,18 @@ class AnsiRenderer extends Renderer {
|
|
|
114
109
|
: unescapeHtml(token.text);
|
|
115
110
|
}
|
|
116
111
|
}
|
|
117
|
-
const
|
|
112
|
+
const createRenderer = (columns) => new AnsiRenderer(columns);
|
|
118
113
|
// Markdown component using custom ANSI renderer
|
|
119
114
|
export const Markdown = React.memo(({ children }) => {
|
|
115
|
+
const { stdout } = useStdout();
|
|
116
|
+
const columns = stdout?.columns ?? 80;
|
|
120
117
|
const ansiContent = useMemo(() => {
|
|
121
118
|
return marked.parse(children, {
|
|
122
|
-
renderer,
|
|
119
|
+
renderer: createRenderer(columns),
|
|
123
120
|
gfm: true,
|
|
124
121
|
breaks: true,
|
|
125
122
|
});
|
|
126
|
-
}, [children]);
|
|
123
|
+
}, [children, columns]);
|
|
127
124
|
return (_jsx(Box, { flexDirection: "column", children: _jsx(Text, { children: ansiContent.trim() }) }));
|
|
128
125
|
});
|
|
129
126
|
// Add display name for debugging
|
|
@@ -6,5 +6,6 @@ export interface MessageListProps {
|
|
|
6
6
|
forceStatic?: boolean;
|
|
7
7
|
version?: string;
|
|
8
8
|
workdir?: string;
|
|
9
|
+
showLoginHint?: boolean;
|
|
9
10
|
}
|
|
10
|
-
export declare const MessageList: React.MemoExoticComponent<({ messages, isExpanded, forceStatic, version, workdir, }: MessageListProps) => import("react/jsx-runtime").JSX.Element>;
|
|
11
|
+
export declare const MessageList: React.MemoExoticComponent<({ messages, isExpanded, forceStatic, version, workdir, showLoginHint, }: MessageListProps) => import("react/jsx-runtime").JSX.Element>;
|
|
@@ -5,7 +5,7 @@ import { Box, Text, Static } from "ink";
|
|
|
5
5
|
import { MessageBlockItem } from "./MessageBlockItem.js";
|
|
6
6
|
const MAX_MESSAGES_COLLAPSED = 30;
|
|
7
7
|
const MAX_MESSAGES_EXPANDED = 10;
|
|
8
|
-
export const MessageList = React.memo(({ messages, isExpanded = false, forceStatic = false, version, workdir, }) => {
|
|
8
|
+
export const MessageList = React.memo(({ messages, isExpanded = false, forceStatic = false, version, workdir, showLoginHint = false, }) => {
|
|
9
9
|
const maxMessages = isExpanded
|
|
10
10
|
? MAX_MESSAGES_EXPANDED
|
|
11
11
|
: MAX_MESSAGES_COLLAPSED;
|
|
@@ -74,7 +74,7 @@ export const MessageList = React.memo(({ messages, isExpanded = false, forceStat
|
|
|
74
74
|
return null;
|
|
75
75
|
}
|
|
76
76
|
return (_jsx(MessageBlockItem, { block: item.block, message: item.message, isExpanded: isExpanded, paddingTop: 1 }, item.key));
|
|
77
|
-
} })), dynamicBlocks.length > 0 && (_jsx(Box, { flexDirection: "column", children: dynamicBlocks.map((item) => (_jsx(MessageBlockItem, { block: item.block, message: item.message, isExpanded: isExpanded, paddingTop: 1 }, item.key))) }))] }));
|
|
77
|
+
} })), showLoginHint && _jsx(Text, { color: "gray", children: "Type /login to authenticate" }), dynamicBlocks.length > 0 && (_jsx(Box, { flexDirection: "column", children: dynamicBlocks.map((item) => (_jsx(MessageBlockItem, { block: item.block, message: item.message, isExpanded: isExpanded, paddingTop: 1 }, item.key))) }))] }));
|
|
78
78
|
});
|
|
79
79
|
// Add display name for debugging
|
|
80
80
|
MessageList.displayName = "MessageList";
|
|
@@ -3,6 +3,7 @@ import { useState, useReducer, useEffect } from "react";
|
|
|
3
3
|
import { Box, Text, useInput } from "ink";
|
|
4
4
|
import { getMessageContent } from "wave-agent-sdk";
|
|
5
5
|
import { rewindSelectorReducer } from "../reducers/rewindSelectorReducer.js";
|
|
6
|
+
import { isUserCheckpointMessage } from "../utils/rewindCheckpoints.js";
|
|
6
7
|
export const RewindCommand = ({ messages: initialMessages, onSelect, onCancel, getFullMessageThread, }) => {
|
|
7
8
|
const [messages, setMessages] = useState(initialMessages);
|
|
8
9
|
const [isLoading, setIsLoading] = useState(!!getFullMessageThread);
|
|
@@ -14,10 +15,11 @@ export const RewindCommand = ({ messages: initialMessages, onSelect, onCancel, g
|
|
|
14
15
|
});
|
|
15
16
|
}
|
|
16
17
|
}, [getFullMessageThread]);
|
|
17
|
-
// Filter user messages as checkpoints, excluding meta messages
|
|
18
|
+
// Filter user messages as checkpoints, excluding meta messages and
|
|
19
|
+
// system-generated user-role messages (task notifications, hook injections)
|
|
18
20
|
const checkpoints = messages
|
|
19
21
|
.map((msg, index) => ({ msg, index }))
|
|
20
|
-
.filter(({ msg }) => msg
|
|
22
|
+
.filter(({ msg }) => isUserCheckpointMessage(msg));
|
|
21
23
|
const MAX_VISIBLE_ITEMS = 3;
|
|
22
24
|
const [state, dispatch] = useReducer(rewindSelectorReducer, {
|
|
23
25
|
selectedIndex: checkpoints.length - 1,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
|
-
export const StatusLine = ({ permissionMode, isShellCommand,
|
|
3
|
+
export const StatusLine = ({ permissionMode, isShellCommand, latestTotalTokens = 0, maxInputTokens = 200000, }) => {
|
|
4
4
|
const percentage = latestTotalTokens > 0
|
|
5
5
|
? Math.min(Math.round((latestTotalTokens / maxInputTokens) * 100), 100)
|
|
6
6
|
: 0;
|
|
7
7
|
const contextColor = percentage > 95 ? "red" : percentage > 80 ? "yellow" : "gray";
|
|
8
|
-
return (_jsxs(Box, { paddingRight: 1, justifyContent: "space-between", width: "100%", children: [isShellCommand ? (_jsxs(Text, { color: "gray", children: ["Shell: ", _jsx(Text, { color: "yellow", children: "Run shell command" })] })) : (
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
return (_jsxs(Box, { paddingRight: 1, justifyContent: "space-between", width: "100%", children: [isShellCommand ? (_jsxs(Text, { color: "gray", children: ["Shell: ", _jsx(Text, { color: "yellow", children: "Run shell command" })] })) : (_jsx(Box, { children: _jsxs(Text, { color: "gray", children: ["Mode:", " ", _jsx(Text, { color: permissionMode === "plan"
|
|
9
|
+
? "yellow"
|
|
10
|
+
: permissionMode === "bypassPermissions"
|
|
11
|
+
? "red"
|
|
12
|
+
: "cyan", bold: permissionMode === "bypassPermissions", children: permissionMode }), " ", "(Shift+Tab to cycle)"] }) })), percentage > 0 && (_jsxs(Text, { color: contextColor, children: [percentage, "% context"] }))] }));
|
|
13
13
|
};
|
|
@@ -75,7 +75,7 @@ function getDisplayLimit(rows) {
|
|
|
75
75
|
}
|
|
76
76
|
export const TaskList = () => {
|
|
77
77
|
const tasks = useTasks();
|
|
78
|
-
const { isTaskListVisible } = useChat();
|
|
78
|
+
const { isTaskListVisible, isBtwActive } = useChat();
|
|
79
79
|
const { stdout } = useStdout();
|
|
80
80
|
const completionTimestampsRef = React.useRef(new Map());
|
|
81
81
|
const previousCompletedIdsRef = React.useRef(null);
|
|
@@ -156,6 +156,7 @@ export const TaskList = () => {
|
|
|
156
156
|
}, [allCompleted, autoHidden, activeTasks.length]);
|
|
157
157
|
if (tasks.length === 0 ||
|
|
158
158
|
!isTaskListVisible ||
|
|
159
|
+
isBtwActive ||
|
|
159
160
|
autoHidden ||
|
|
160
161
|
(allCompleted && !hadIncompleteRef.current)) {
|
|
161
162
|
return null;
|
|
@@ -4,5 +4,6 @@ interface ToolDisplayProps {
|
|
|
4
4
|
block: ToolBlock;
|
|
5
5
|
isExpanded?: boolean;
|
|
6
6
|
}
|
|
7
|
+
export declare const getToolStatusColor: (stage: ToolBlock["stage"], success?: boolean, error?: string | Error) => string;
|
|
7
8
|
export declare const ToolDisplay: React.FC<ToolDisplayProps>;
|
|
8
9
|
export {};
|
|
@@ -2,19 +2,27 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { getLastLines } from "wave-agent-sdk";
|
|
4
4
|
import { DiffDisplay } from "./DiffDisplay.js";
|
|
5
|
+
// Status dot color for a tool block. In-flight stages (start/streaming/running)
|
|
6
|
+
// never show red — the outcome isn't known until the tool reaches "end".
|
|
7
|
+
// An explicit error overrides everything.
|
|
8
|
+
export const getToolStatusColor = (stage, success, error) => {
|
|
9
|
+
if (error)
|
|
10
|
+
return "red";
|
|
11
|
+
if (stage === "start" || stage === "streaming")
|
|
12
|
+
return "gray";
|
|
13
|
+
if (stage === "running")
|
|
14
|
+
return "yellow";
|
|
15
|
+
if (success)
|
|
16
|
+
return "green";
|
|
17
|
+
if (success === false)
|
|
18
|
+
return "red";
|
|
19
|
+
return "gray"; // Unknown state or no state information
|
|
20
|
+
};
|
|
5
21
|
export const ToolDisplay = ({ block, isExpanded = false, }) => {
|
|
6
22
|
const { parameters, result, compactParams, stage, success, error, name } = block;
|
|
7
23
|
// Directly use compactParams
|
|
8
24
|
// (no change needed as we destructured it above)
|
|
9
|
-
const getStatusColor = () =>
|
|
10
|
-
if (stage === "running")
|
|
11
|
-
return "yellow";
|
|
12
|
-
if (success)
|
|
13
|
-
return "green";
|
|
14
|
-
if (error || success === false)
|
|
15
|
-
return "red";
|
|
16
|
-
return "gray"; // Unknown state or no state information
|
|
17
|
-
};
|
|
25
|
+
const getStatusColor = () => getToolStatusColor(stage, success, error);
|
|
18
26
|
const hasImages = () => {
|
|
19
27
|
return block.images && block.images.length > 0;
|
|
20
28
|
};
|
|
@@ -77,10 +77,4 @@ export const AVAILABLE_COMMANDS = [
|
|
|
77
77
|
description: "Compact conversation history to reduce context usage",
|
|
78
78
|
handler: () => { },
|
|
79
79
|
},
|
|
80
|
-
{
|
|
81
|
-
id: "goal",
|
|
82
|
-
name: "goal",
|
|
83
|
-
description: "Set, check, or clear an autonomous goal for the session",
|
|
84
|
-
handler: () => { },
|
|
85
|
-
},
|
|
86
80
|
];
|
|
@@ -9,16 +9,17 @@ export interface ChatContextType {
|
|
|
9
9
|
isExpanded: boolean;
|
|
10
10
|
isTaskListVisible: boolean;
|
|
11
11
|
setIsTaskListVisible: (visible: boolean) => void;
|
|
12
|
+
isBtwActive: boolean;
|
|
13
|
+
setIsBtwActive: (active: boolean) => void;
|
|
12
14
|
queuedMessages: QueuedMessage[];
|
|
13
15
|
sessionId: string;
|
|
14
16
|
sendMessage: (content: string, images?: Array<{
|
|
15
17
|
path: string;
|
|
16
18
|
mimeType: string;
|
|
17
19
|
}>, longTextMap?: Record<string, string>) => Promise<void>;
|
|
18
|
-
askBtw: (question: string) => Promise<string>;
|
|
20
|
+
askBtw: (question: string, abortSignal?: AbortSignal, onContent?: (content: string) => void) => Promise<string>;
|
|
19
21
|
clearMessages: () => Promise<void>;
|
|
20
22
|
compact: (instructions?: string) => Promise<void>;
|
|
21
|
-
goalCommand: (args?: string) => Promise<void>;
|
|
22
23
|
abortMessage: () => void;
|
|
23
24
|
recallQueuedMessage: () => QueuedMessage | null;
|
|
24
25
|
removeQueuedMessageById: (id: string) => boolean;
|
|
@@ -74,9 +75,6 @@ export interface ChatContextType {
|
|
|
74
75
|
workdir?: string;
|
|
75
76
|
recreateAgent: () => void;
|
|
76
77
|
triggerWorktreeRemoveHook: (worktreePath: string) => Promise<void>;
|
|
77
|
-
isGoalActive: boolean;
|
|
78
|
-
goalElapsed?: string;
|
|
79
|
-
isGoalEvaluating: boolean;
|
|
80
78
|
}
|
|
81
79
|
export declare const useChat: () => ChatContextType;
|
|
82
80
|
export interface ChatProviderProps extends BaseAppProps {
|