wave-code 0.17.0 → 0.17.2
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/acp/agent.d.ts +1 -0
- package/dist/acp/agent.d.ts.map +1 -1
- package/dist/acp/agent.js +116 -1
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +5 -2
- package/dist/components/InputBox.d.ts +2 -0
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +29 -8
- package/dist/components/LoadingIndicator.d.ts +2 -1
- package/dist/components/LoadingIndicator.d.ts.map +1 -1
- package/dist/components/LoadingIndicator.js +2 -2
- package/dist/components/QueuedMessageList.d.ts.map +1 -1
- package/dist/components/QueuedMessageList.js +10 -10
- package/dist/components/StatusLine.d.ts +2 -0
- package/dist/components/StatusLine.d.ts.map +1 -1
- package/dist/components/StatusLine.js +6 -6
- package/dist/components/TaskList.d.ts +3 -0
- package/dist/components/TaskList.d.ts.map +1 -1
- package/dist/components/TaskList.js +171 -28
- package/dist/components/TaskNotificationMessage.d.ts.map +1 -1
- package/dist/components/TaskNotificationMessage.js +1 -0
- package/dist/components/WorkflowManager.d.ts +6 -0
- package/dist/components/WorkflowManager.d.ts.map +1 -0
- package/dist/components/WorkflowManager.js +102 -0
- package/dist/constants/commands.d.ts.map +1 -1
- package/dist/constants/commands.js +6 -0
- package/dist/contexts/useChat.d.ts +8 -1
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +68 -4
- package/dist/hooks/useInputManager.d.ts +2 -0
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +22 -13
- package/dist/managers/inputHandlers.d.ts.map +1 -1
- package/dist/managers/inputHandlers.js +6 -3
- package/dist/managers/inputReducer.d.ts +10 -0
- package/dist/managers/inputReducer.d.ts.map +1 -1
- package/dist/managers/inputReducer.js +41 -4
- package/dist/print-cli.d.ts.map +1 -1
- package/dist/print-cli.js +3 -31
- package/dist/reducers/workflowManagerReducer.d.ts +41 -0
- package/dist/reducers/workflowManagerReducer.d.ts.map +1 -0
- package/dist/reducers/workflowManagerReducer.js +100 -0
- package/package.json +2 -2
- package/src/acp/agent.ts +137 -1
- package/src/components/ChatInterface.tsx +10 -1
- package/src/components/InputBox.tsx +43 -3
- package/src/components/LoadingIndicator.tsx +4 -1
- package/src/components/QueuedMessageList.tsx +7 -3
- package/src/components/StatusLine.tsx +28 -16
- package/src/components/TaskList.tsx +213 -19
- package/src/components/TaskNotificationMessage.tsx +1 -0
- package/src/components/WorkflowManager.tsx +320 -0
- package/src/constants/commands.ts +6 -0
- package/src/contexts/useChat.tsx +83 -4
- package/src/hooks/useInputManager.ts +25 -13
- package/src/managers/inputHandlers.ts +5 -4
- package/src/managers/inputReducer.ts +54 -6
- package/src/print-cli.ts +3 -37
- package/src/reducers/workflowManagerReducer.ts +143 -0
package/src/acp/agent.ts
CHANGED
|
@@ -17,6 +17,10 @@ import {
|
|
|
17
17
|
ASK_USER_QUESTION_TOOL_NAME,
|
|
18
18
|
AskUserQuestion,
|
|
19
19
|
AskUserQuestionOption,
|
|
20
|
+
type Message,
|
|
21
|
+
type TextBlock,
|
|
22
|
+
type ReasoningBlock,
|
|
23
|
+
type ToolBlock,
|
|
20
24
|
} from "wave-agent-sdk";
|
|
21
25
|
import { logger } from "../utils/logger.js";
|
|
22
26
|
import {
|
|
@@ -98,7 +102,7 @@ export class WaveAcpAgent implements AcpAgent {
|
|
|
98
102
|
|
|
99
103
|
private getSessionConfigOptions(agent: WaveAgent): SessionConfigOption[] {
|
|
100
104
|
const configuredModels = agent.getConfiguredModels();
|
|
101
|
-
const currentModel = agent.getModelConfig().model;
|
|
105
|
+
const currentModel = agent.getModelConfig().model || "";
|
|
102
106
|
|
|
103
107
|
return [
|
|
104
108
|
{
|
|
@@ -262,6 +266,9 @@ export class WaveAcpAgent implements AcpAgent {
|
|
|
262
266
|
logger.info(`Loading session: ${sessionId} in ${cwd}`);
|
|
263
267
|
const agent = await this.createAgent(sessionId, cwd, mcpServers);
|
|
264
268
|
|
|
269
|
+
// Replay conversation history via session/update notifications per ACP spec
|
|
270
|
+
await this.replayConversationHistory(agent);
|
|
271
|
+
|
|
265
272
|
return {
|
|
266
273
|
modes: this.getSessionModeState(agent),
|
|
267
274
|
configOptions: this.getSessionConfigOptions(agent),
|
|
@@ -799,6 +806,135 @@ export class WaveAcpAgent implements AcpAgent {
|
|
|
799
806
|
}
|
|
800
807
|
}
|
|
801
808
|
|
|
809
|
+
private async replayConversationHistory(agent: WaveAgent): Promise<void> {
|
|
810
|
+
const sessionId = agent.sessionId as AcpSessionId;
|
|
811
|
+
|
|
812
|
+
let history: Message[];
|
|
813
|
+
try {
|
|
814
|
+
const thread = await agent.getFullMessageThread();
|
|
815
|
+
history = thread.messages;
|
|
816
|
+
} catch {
|
|
817
|
+
// Fallback to in-memory messages if full thread fails
|
|
818
|
+
history = agent.messages;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
for (const message of history) {
|
|
822
|
+
if (message.isMeta) continue;
|
|
823
|
+
|
|
824
|
+
const messageId = message.id;
|
|
825
|
+
|
|
826
|
+
for (const block of message.blocks) {
|
|
827
|
+
if (block.type === "text") {
|
|
828
|
+
const textBlock = block as TextBlock;
|
|
829
|
+
const update =
|
|
830
|
+
message.role === "user"
|
|
831
|
+
? {
|
|
832
|
+
sessionUpdate: "user_message_chunk" as const,
|
|
833
|
+
content: { type: "text" as const, text: textBlock.content },
|
|
834
|
+
messageId,
|
|
835
|
+
}
|
|
836
|
+
: {
|
|
837
|
+
sessionUpdate: "agent_message_chunk" as const,
|
|
838
|
+
content: { type: "text" as const, text: textBlock.content },
|
|
839
|
+
messageId,
|
|
840
|
+
};
|
|
841
|
+
this.connection.sessionUpdate({ sessionId, update });
|
|
842
|
+
} else if (block.type === "reasoning") {
|
|
843
|
+
const reasoningBlock = block as ReasoningBlock;
|
|
844
|
+
this.connection.sessionUpdate({
|
|
845
|
+
sessionId,
|
|
846
|
+
update: {
|
|
847
|
+
sessionUpdate: "agent_thought_chunk",
|
|
848
|
+
content: { type: "text", text: reasoningBlock.content },
|
|
849
|
+
messageId,
|
|
850
|
+
},
|
|
851
|
+
});
|
|
852
|
+
} else if (block.type === "tool") {
|
|
853
|
+
const toolBlock = block as ToolBlock;
|
|
854
|
+
const toolCallId =
|
|
855
|
+
toolBlock.id ||
|
|
856
|
+
"replay-" + Math.random().toString(36).substring(2, 9);
|
|
857
|
+
const effectiveName = toolBlock.name || "Tool";
|
|
858
|
+
const effectiveCompactParams = toolBlock.compactParams;
|
|
859
|
+
|
|
860
|
+
const displayTitle =
|
|
861
|
+
effectiveName && effectiveCompactParams
|
|
862
|
+
? `${effectiveName}: ${effectiveCompactParams}`
|
|
863
|
+
: effectiveName;
|
|
864
|
+
|
|
865
|
+
let parsedParameters: Record<string, unknown> | undefined;
|
|
866
|
+
if (toolBlock.parameters) {
|
|
867
|
+
try {
|
|
868
|
+
const parsed = JSON.parse(toolBlock.parameters);
|
|
869
|
+
parsedParameters = Array.isArray(parsed)
|
|
870
|
+
? { args: parsed }
|
|
871
|
+
: parsed;
|
|
872
|
+
} catch {
|
|
873
|
+
// Ignore parse errors
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
const content =
|
|
878
|
+
effectiveName && (parsedParameters || toolBlock.shortResult)
|
|
879
|
+
? this.getToolContent(
|
|
880
|
+
effectiveName,
|
|
881
|
+
parsedParameters,
|
|
882
|
+
toolBlock.shortResult,
|
|
883
|
+
)
|
|
884
|
+
: undefined;
|
|
885
|
+
const locations =
|
|
886
|
+
effectiveName && parsedParameters
|
|
887
|
+
? this.getToolLocations(effectiveName, parsedParameters)
|
|
888
|
+
: undefined;
|
|
889
|
+
const kind = effectiveName
|
|
890
|
+
? this.getToolKind(effectiveName)
|
|
891
|
+
: undefined;
|
|
892
|
+
|
|
893
|
+
// Emit tool_call (creation)
|
|
894
|
+
this.connection.sessionUpdate({
|
|
895
|
+
sessionId,
|
|
896
|
+
update: {
|
|
897
|
+
sessionUpdate: "tool_call",
|
|
898
|
+
toolCallId,
|
|
899
|
+
title: displayTitle,
|
|
900
|
+
status: "pending",
|
|
901
|
+
content,
|
|
902
|
+
locations,
|
|
903
|
+
kind,
|
|
904
|
+
rawInput: parsedParameters,
|
|
905
|
+
},
|
|
906
|
+
});
|
|
907
|
+
|
|
908
|
+
// Emit tool_call_update with final status
|
|
909
|
+
const status: ToolCallStatus =
|
|
910
|
+
toolBlock.stage === "end"
|
|
911
|
+
? toolBlock.success
|
|
912
|
+
? "completed"
|
|
913
|
+
: "failed"
|
|
914
|
+
: toolBlock.stage === "running"
|
|
915
|
+
? "in_progress"
|
|
916
|
+
: "pending";
|
|
917
|
+
|
|
918
|
+
this.connection.sessionUpdate({
|
|
919
|
+
sessionId,
|
|
920
|
+
update: {
|
|
921
|
+
sessionUpdate: "tool_call_update",
|
|
922
|
+
toolCallId,
|
|
923
|
+
status,
|
|
924
|
+
title: displayTitle,
|
|
925
|
+
rawOutput: toolBlock.result || toolBlock.error,
|
|
926
|
+
content,
|
|
927
|
+
locations,
|
|
928
|
+
kind,
|
|
929
|
+
rawInput: parsedParameters,
|
|
930
|
+
},
|
|
931
|
+
});
|
|
932
|
+
}
|
|
933
|
+
// Skip: image, bang, compact, error, file_history, task_notification blocks
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
|
|
802
938
|
private createCallbacks(sessionId: string): AgentOptions["callbacks"] {
|
|
803
939
|
const getAgent = () => this.agents.get(sessionId);
|
|
804
940
|
const toolStates = new Map<
|
|
@@ -37,6 +37,9 @@ export const ChatInterface: React.FC = () => {
|
|
|
37
37
|
workdir,
|
|
38
38
|
remountKey,
|
|
39
39
|
requestRemount,
|
|
40
|
+
isGoalActive,
|
|
41
|
+
goalElapsed,
|
|
42
|
+
isGoalEvaluating,
|
|
40
43
|
} = useChat();
|
|
41
44
|
|
|
42
45
|
const displayMessages = messages;
|
|
@@ -80,11 +83,15 @@ export const ChatInterface: React.FC = () => {
|
|
|
80
83
|
|
|
81
84
|
{!isConfirmationVisible && !isExpanded && (
|
|
82
85
|
<>
|
|
83
|
-
{(isLoading ||
|
|
86
|
+
{(isLoading ||
|
|
87
|
+
isCommandRunning ||
|
|
88
|
+
isCompacting ||
|
|
89
|
+
isGoalEvaluating) && (
|
|
84
90
|
<LoadingIndicator
|
|
85
91
|
isLoading={isLoading}
|
|
86
92
|
isCommandRunning={isCommandRunning}
|
|
87
93
|
isCompacting={isCompacting}
|
|
94
|
+
isGoalEvaluating={isGoalEvaluating}
|
|
88
95
|
latestTotalTokens={latestTotalTokens}
|
|
89
96
|
/>
|
|
90
97
|
)}
|
|
@@ -102,6 +109,8 @@ export const ChatInterface: React.FC = () => {
|
|
|
102
109
|
hasSlashCommand={hasSlashCommand}
|
|
103
110
|
latestTotalTokens={latestTotalTokens}
|
|
104
111
|
maxInputTokens={maxInputTokens}
|
|
112
|
+
isGoalActive={isGoalActive}
|
|
113
|
+
goalElapsed={goalElapsed}
|
|
105
114
|
/>
|
|
106
115
|
</>
|
|
107
116
|
)}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useEffect } from "react";
|
|
1
|
+
import React, { useEffect, useRef, useCallback } from "react";
|
|
2
2
|
import { Box, Text } from "ink";
|
|
3
3
|
import { useInput } from "ink";
|
|
4
4
|
import { FileSelector } from "./FileSelector.js";
|
|
@@ -12,6 +12,7 @@ import { StatusCommand } from "./StatusCommand.js";
|
|
|
12
12
|
import { LoginCommand } from "./LoginCommand.js";
|
|
13
13
|
import { PluginManagerShell } from "./PluginManagerShell.js";
|
|
14
14
|
import { ModelSelector } from "./ModelSelector.js";
|
|
15
|
+
import { WorkflowManager } from "./WorkflowManager.js";
|
|
15
16
|
import { StatusLine } from "./StatusLine.js";
|
|
16
17
|
import { BtwDisplay } from "./BtwDisplay.js";
|
|
17
18
|
import { useInputManager } from "../hooks/useInputManager.js";
|
|
@@ -47,6 +48,9 @@ export interface InputBoxProps {
|
|
|
47
48
|
// Token usage
|
|
48
49
|
latestTotalTokens?: number;
|
|
49
50
|
maxInputTokens?: number;
|
|
51
|
+
// Goal state
|
|
52
|
+
isGoalActive?: boolean;
|
|
53
|
+
goalElapsed?: string;
|
|
50
54
|
}
|
|
51
55
|
|
|
52
56
|
export const InputBox: React.FC<InputBoxProps> = ({
|
|
@@ -59,6 +63,8 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
59
63
|
hasSlashCommand = () => false,
|
|
60
64
|
latestTotalTokens = 0,
|
|
61
65
|
maxInputTokens = 128000,
|
|
66
|
+
isGoalActive,
|
|
67
|
+
goalElapsed,
|
|
62
68
|
}) => {
|
|
63
69
|
const {
|
|
64
70
|
permissionMode: chatPermissionMode,
|
|
@@ -74,8 +80,23 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
74
80
|
configuredModels,
|
|
75
81
|
setModel,
|
|
76
82
|
recreateAgent,
|
|
83
|
+
recallQueuedMessage,
|
|
84
|
+
queuedMessages,
|
|
77
85
|
} = useChat();
|
|
78
86
|
|
|
87
|
+
// Ref to hold setInputText so queue callbacks can access it before useInputManager returns
|
|
88
|
+
const setInputTextRef = useRef<(text: string) => void>(() => {});
|
|
89
|
+
|
|
90
|
+
const hasQueuedMessages = (queuedMessages?.length ?? 0) > 0;
|
|
91
|
+
|
|
92
|
+
const onRecallQueuedMessage = useCallback(() => {
|
|
93
|
+
const msg = recallQueuedMessage();
|
|
94
|
+
if (msg) {
|
|
95
|
+
const prefix = msg.type === "bang" ? "!" : "";
|
|
96
|
+
setInputTextRef.current(prefix + msg.content);
|
|
97
|
+
}
|
|
98
|
+
}, [recallQueuedMessage]);
|
|
99
|
+
|
|
79
100
|
// Input manager with all input state and functionality (including images)
|
|
80
101
|
const {
|
|
81
102
|
inputText,
|
|
@@ -110,6 +131,7 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
110
131
|
showLoginCommand,
|
|
111
132
|
showPluginManager,
|
|
112
133
|
showModelSelector,
|
|
134
|
+
showWorkflowManager,
|
|
113
135
|
setShowBackgroundTaskManager,
|
|
114
136
|
setShowMcpManager,
|
|
115
137
|
setShowRewindManager,
|
|
@@ -118,6 +140,7 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
118
140
|
setShowLoginCommand,
|
|
119
141
|
setShowPluginManager,
|
|
120
142
|
setShowModelSelector,
|
|
143
|
+
setShowWorkflowManager,
|
|
121
144
|
// Permission mode
|
|
122
145
|
permissionMode,
|
|
123
146
|
setPermissionMode,
|
|
@@ -127,6 +150,8 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
127
150
|
handleInput,
|
|
128
151
|
// Manager ready state
|
|
129
152
|
isManagerReady,
|
|
153
|
+
// Direct state setters
|
|
154
|
+
setInputText,
|
|
130
155
|
} = useInputManager({
|
|
131
156
|
onSendMessage: sendMessage,
|
|
132
157
|
onAskBtw: askBtw,
|
|
@@ -137,8 +162,15 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
137
162
|
sessionId,
|
|
138
163
|
workdir: workingDirectory,
|
|
139
164
|
getFullMessageThread,
|
|
165
|
+
hasQueuedMessages,
|
|
166
|
+
onRecallQueuedMessage,
|
|
140
167
|
});
|
|
141
168
|
|
|
169
|
+
// Keep setInputText ref updated for queue callbacks
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
setInputTextRef.current = setInputText;
|
|
172
|
+
}, [setInputText]);
|
|
173
|
+
|
|
142
174
|
// Sync permission mode from useChat to InputManager
|
|
143
175
|
useEffect(() => {
|
|
144
176
|
setPermissionMode(chatPermissionMode);
|
|
@@ -157,7 +189,8 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
157
189
|
showPluginManager ||
|
|
158
190
|
showModelSelector ||
|
|
159
191
|
showBackgroundTaskManager ||
|
|
160
|
-
showMcpManager
|
|
192
|
+
showMcpManager ||
|
|
193
|
+
showWorkflowManager
|
|
161
194
|
) {
|
|
162
195
|
return;
|
|
163
196
|
}
|
|
@@ -291,13 +324,18 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
291
324
|
/>
|
|
292
325
|
)}
|
|
293
326
|
|
|
327
|
+
{showWorkflowManager && (
|
|
328
|
+
<WorkflowManager onCancel={() => setShowWorkflowManager(false)} />
|
|
329
|
+
)}
|
|
330
|
+
|
|
294
331
|
{showBackgroundTaskManager ||
|
|
295
332
|
showMcpManager ||
|
|
296
333
|
showRewindManager ||
|
|
297
334
|
showHelp ||
|
|
298
335
|
showStatusCommand ||
|
|
299
336
|
showLoginCommand ||
|
|
300
|
-
showPluginManager ||
|
|
337
|
+
showPluginManager ||
|
|
338
|
+
showWorkflowManager || (
|
|
301
339
|
<Box flexDirection="column">
|
|
302
340
|
<Box
|
|
303
341
|
borderStyle="single"
|
|
@@ -330,6 +368,8 @@ export const InputBox: React.FC<InputBoxProps> = ({
|
|
|
330
368
|
permissionMode={permissionMode}
|
|
331
369
|
isShellCommand={isShellCommand}
|
|
332
370
|
isBtwActive={btwState.isActive}
|
|
371
|
+
isGoalActive={isGoalActive}
|
|
372
|
+
goalElapsed={goalElapsed}
|
|
333
373
|
latestTotalTokens={latestTotalTokens}
|
|
334
374
|
maxInputTokens={maxInputTokens}
|
|
335
375
|
/>
|
|
@@ -5,6 +5,7 @@ export interface LoadingIndicatorProps {
|
|
|
5
5
|
isLoading?: boolean;
|
|
6
6
|
isCommandRunning?: boolean;
|
|
7
7
|
isCompacting?: boolean;
|
|
8
|
+
isGoalEvaluating?: boolean;
|
|
8
9
|
latestTotalTokens?: number;
|
|
9
10
|
}
|
|
10
11
|
|
|
@@ -12,11 +13,12 @@ export const LoadingIndicator = ({
|
|
|
12
13
|
isLoading = false,
|
|
13
14
|
isCommandRunning = false,
|
|
14
15
|
isCompacting = false,
|
|
16
|
+
isGoalEvaluating = false,
|
|
15
17
|
latestTotalTokens = 0,
|
|
16
18
|
}: LoadingIndicatorProps) => {
|
|
17
19
|
return (
|
|
18
20
|
<Box flexDirection="column">
|
|
19
|
-
{isLoading && !isCompacting && (
|
|
21
|
+
{isLoading && !isCompacting && !isGoalEvaluating && (
|
|
20
22
|
<Box>
|
|
21
23
|
<Text color="yellow">✻ AI is thinking... </Text>
|
|
22
24
|
{latestTotalTokens > 0 && (
|
|
@@ -49,6 +51,7 @@ export const LoadingIndicator = ({
|
|
|
49
51
|
{isCompacting && (
|
|
50
52
|
<Text color="magenta">✻ Compacting message history...</Text>
|
|
51
53
|
)}
|
|
54
|
+
{isGoalEvaluating && <Text color="cyan">✻ Evaluating goal...</Text>}
|
|
52
55
|
</Box>
|
|
53
56
|
);
|
|
54
57
|
};
|
|
@@ -18,15 +18,19 @@ export const QueuedMessageList: React.FC = () => {
|
|
|
18
18
|
const displayText = prefix + (content || (hasImages ? "[Images]" : ""));
|
|
19
19
|
|
|
20
20
|
return (
|
|
21
|
-
<Box key={index}>
|
|
21
|
+
<Box key={msg.id ?? index}>
|
|
22
|
+
<Text color="gray">[{index + 1}] </Text>
|
|
22
23
|
<Text color="gray" italic>
|
|
23
|
-
{displayText.length >
|
|
24
|
-
? `${displayText.substring(0,
|
|
24
|
+
{displayText.length > 55
|
|
25
|
+
? `${displayText.substring(0, 52)}...`
|
|
25
26
|
: displayText}
|
|
26
27
|
</Text>
|
|
27
28
|
</Box>
|
|
28
29
|
);
|
|
29
30
|
})}
|
|
31
|
+
<Text color="gray" dimColor>
|
|
32
|
+
{" "}↑ recall
|
|
33
|
+
</Text>
|
|
30
34
|
</Box>
|
|
31
35
|
);
|
|
32
36
|
};
|
|
@@ -5,6 +5,8 @@ export interface StatusLineProps {
|
|
|
5
5
|
permissionMode: string;
|
|
6
6
|
isShellCommand: boolean;
|
|
7
7
|
isBtwActive: boolean;
|
|
8
|
+
isGoalActive?: boolean;
|
|
9
|
+
goalElapsed?: string;
|
|
8
10
|
latestTotalTokens?: number;
|
|
9
11
|
maxInputTokens?: number;
|
|
10
12
|
}
|
|
@@ -13,6 +15,8 @@ export const StatusLine: React.FC<StatusLineProps> = ({
|
|
|
13
15
|
permissionMode,
|
|
14
16
|
isShellCommand,
|
|
15
17
|
isBtwActive,
|
|
18
|
+
isGoalActive,
|
|
19
|
+
goalElapsed,
|
|
16
20
|
latestTotalTokens = 0,
|
|
17
21
|
maxInputTokens = 128000,
|
|
18
22
|
}) => {
|
|
@@ -35,22 +39,30 @@ export const StatusLine: React.FC<StatusLineProps> = ({
|
|
|
35
39
|
Shell: <Text color="yellow">Run shell command</Text>
|
|
36
40
|
</Text>
|
|
37
41
|
) : (
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
42
|
+
<Box>
|
|
43
|
+
{isGoalActive && (
|
|
44
|
+
<Text color="gray">
|
|
45
|
+
<Text color="cyan">◎ /goal</Text> active{" "}
|
|
46
|
+
{goalElapsed && <Text>({goalElapsed})</Text>} |{" "}
|
|
47
|
+
</Text>
|
|
48
|
+
)}
|
|
49
|
+
<Text color="gray">
|
|
50
|
+
Mode:{" "}
|
|
51
|
+
<Text
|
|
52
|
+
color={
|
|
53
|
+
permissionMode === "plan"
|
|
54
|
+
? "yellow"
|
|
55
|
+
: permissionMode === "bypassPermissions"
|
|
56
|
+
? "red"
|
|
57
|
+
: "cyan"
|
|
58
|
+
}
|
|
59
|
+
bold={permissionMode === "bypassPermissions"}
|
|
60
|
+
>
|
|
61
|
+
{permissionMode}
|
|
62
|
+
</Text>{" "}
|
|
63
|
+
(Shift+Tab to cycle)
|
|
64
|
+
</Text>
|
|
65
|
+
</Box>
|
|
54
66
|
)}
|
|
55
67
|
{percentage > 0 && (
|
|
56
68
|
<Text color={contextColor}>{percentage}% context</Text>
|