wave-code 0.0.5 → 0.0.8
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/README.md +3 -3
- package/dist/cli.d.ts +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/components/App.d.ts +1 -0
- package/dist/components/App.d.ts.map +1 -1
- package/dist/components/App.js +4 -4
- package/dist/components/BashHistorySelector.d.ts.map +1 -1
- package/dist/components/BashHistorySelector.js +17 -3
- package/dist/components/ChatInterface.d.ts.map +1 -1
- package/dist/components/ChatInterface.js +6 -24
- package/dist/components/CommandSelector.js +4 -4
- package/dist/components/Confirmation.d.ts +11 -0
- package/dist/components/Confirmation.d.ts.map +1 -0
- package/dist/components/Confirmation.js +148 -0
- package/dist/components/DiffDisplay.d.ts +8 -0
- package/dist/components/DiffDisplay.d.ts.map +1 -0
- package/dist/components/DiffDisplay.js +168 -0
- package/dist/components/FileSelector.d.ts +2 -4
- package/dist/components/FileSelector.d.ts.map +1 -1
- package/dist/components/FileSelector.js +2 -2
- package/dist/components/InputBox.d.ts.map +1 -1
- package/dist/components/InputBox.js +30 -50
- package/dist/components/Markdown.d.ts +6 -0
- package/dist/components/Markdown.d.ts.map +1 -0
- package/dist/components/Markdown.js +22 -0
- package/dist/components/MemoryDisplay.js +1 -1
- package/dist/components/MessageItem.d.ts +8 -0
- package/dist/components/MessageItem.d.ts.map +1 -0
- package/dist/components/MessageItem.js +15 -0
- package/dist/components/MessageList.d.ts +1 -1
- package/dist/components/MessageList.d.ts.map +1 -1
- package/dist/components/MessageList.js +33 -33
- package/dist/components/ReasoningDisplay.d.ts +8 -0
- package/dist/components/ReasoningDisplay.d.ts.map +1 -0
- package/dist/components/ReasoningDisplay.js +10 -0
- package/dist/components/SubagentBlock.d.ts +0 -1
- package/dist/components/SubagentBlock.d.ts.map +1 -1
- package/dist/components/SubagentBlock.js +29 -30
- package/dist/components/ToolResultDisplay.d.ts.map +1 -1
- package/dist/components/ToolResultDisplay.js +6 -5
- package/dist/contexts/useChat.d.ts +14 -2
- package/dist/contexts/useChat.d.ts.map +1 -1
- package/dist/contexts/useChat.js +128 -17
- package/dist/hooks/useInputManager.d.ts +6 -1
- package/dist/hooks/useInputManager.d.ts.map +1 -1
- package/dist/hooks/useInputManager.js +32 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -5
- package/dist/managers/InputManager.d.ts +11 -1
- package/dist/managers/InputManager.d.ts.map +1 -1
- package/dist/managers/InputManager.js +77 -26
- package/dist/print-cli.d.ts +2 -0
- package/dist/print-cli.d.ts.map +1 -1
- package/dist/print-cli.js +121 -23
- package/dist/utils/toolParameterTransforms.d.ts +23 -0
- package/dist/utils/toolParameterTransforms.d.ts.map +1 -0
- package/dist/utils/toolParameterTransforms.js +77 -0
- package/dist/utils/usageSummary.d.ts +6 -0
- package/dist/utils/usageSummary.d.ts.map +1 -1
- package/dist/utils/usageSummary.js +72 -0
- package/package.json +13 -8
- package/src/cli.tsx +3 -1
- package/src/components/App.tsx +7 -3
- package/src/components/BashHistorySelector.tsx +26 -3
- package/src/components/ChatInterface.tsx +38 -54
- package/src/components/CommandSelector.tsx +5 -5
- package/src/components/Confirmation.tsx +253 -0
- package/src/components/DiffDisplay.tsx +300 -0
- package/src/components/FileSelector.tsx +4 -6
- package/src/components/InputBox.tsx +58 -87
- package/src/components/Markdown.tsx +29 -0
- package/src/components/MemoryDisplay.tsx +1 -1
- package/src/components/MessageItem.tsx +96 -0
- package/src/components/MessageList.tsx +140 -202
- package/src/components/ReasoningDisplay.tsx +33 -0
- package/src/components/SubagentBlock.tsx +56 -84
- package/src/components/ToolResultDisplay.tsx +9 -5
- package/src/contexts/useChat.tsx +194 -21
- package/src/hooks/useInputManager.ts +40 -3
- package/src/index.ts +45 -5
- package/src/managers/InputManager.ts +101 -27
- package/src/print-cli.ts +143 -21
- package/src/utils/toolParameterTransforms.ts +104 -0
- package/src/utils/usageSummary.ts +109 -0
- package/dist/components/DiffViewer.d.ts +0 -9
- package/dist/components/DiffViewer.d.ts.map +0 -1
- package/dist/components/DiffViewer.js +0 -221
- package/dist/utils/fileSearch.d.ts +0 -20
- package/dist/utils/fileSearch.d.ts.map +0 -1
- package/dist/utils/fileSearch.js +0 -102
- package/src/components/DiffViewer.tsx +0 -321
- package/src/utils/fileSearch.ts +0 -133
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { FileItem } from "../components/FileSelector.js";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
searchFiles as searchFilesUtil,
|
|
4
|
+
PermissionMode,
|
|
5
|
+
Logger,
|
|
6
|
+
} from "wave-agent-sdk";
|
|
3
7
|
import { readClipboardImage } from "../utils/clipboard.js";
|
|
4
8
|
import type { Key } from "ink";
|
|
5
9
|
|
|
@@ -42,6 +46,8 @@ export interface InputManagerCallbacks {
|
|
|
42
46
|
onSaveMemory?: (message: string, type: "project" | "user") => Promise<void>;
|
|
43
47
|
onAbortMessage?: () => void;
|
|
44
48
|
onResetHistoryNavigation?: () => void;
|
|
49
|
+
onPermissionModeChange?: (mode: PermissionMode) => void;
|
|
50
|
+
logger?: Logger;
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
export class InputManager {
|
|
@@ -93,18 +99,26 @@ export class InputManager {
|
|
|
93
99
|
private showBashManager: boolean = false;
|
|
94
100
|
private showMcpManager: boolean = false;
|
|
95
101
|
|
|
102
|
+
// Permission mode state
|
|
103
|
+
private permissionMode: PermissionMode = "default";
|
|
104
|
+
|
|
96
105
|
// Flag to prevent handleInput conflicts when selector selection occurs
|
|
97
106
|
private selectorJustUsed: boolean = false;
|
|
98
107
|
|
|
99
108
|
private callbacks: InputManagerCallbacks;
|
|
109
|
+
private logger?: Logger;
|
|
100
110
|
|
|
101
111
|
constructor(callbacks: InputManagerCallbacks = {}) {
|
|
102
112
|
this.callbacks = callbacks;
|
|
113
|
+
this.logger = callbacks.logger;
|
|
103
114
|
}
|
|
104
115
|
|
|
105
116
|
// Update callbacks
|
|
106
117
|
updateCallbacks(callbacks: Partial<InputManagerCallbacks>) {
|
|
107
118
|
this.callbacks = { ...this.callbacks, ...callbacks };
|
|
119
|
+
if (callbacks.logger) {
|
|
120
|
+
this.logger = callbacks.logger;
|
|
121
|
+
}
|
|
108
122
|
}
|
|
109
123
|
|
|
110
124
|
// Core input methods
|
|
@@ -487,6 +501,16 @@ export class InputManager {
|
|
|
487
501
|
return command; // Return command to execute
|
|
488
502
|
}
|
|
489
503
|
|
|
504
|
+
handleBashHistoryExecuteAndSend(command: string): void {
|
|
505
|
+
const commandToExecute = this.handleBashHistoryExecute(command);
|
|
506
|
+
// Clear input box and execute command, ensure command starts with !
|
|
507
|
+
const bashCommand = commandToExecute.startsWith("!")
|
|
508
|
+
? commandToExecute
|
|
509
|
+
: `!${commandToExecute}`;
|
|
510
|
+
this.clearInput();
|
|
511
|
+
this.callbacks.onSendMessage?.(bashCommand);
|
|
512
|
+
}
|
|
513
|
+
|
|
490
514
|
checkForExclamationDeletion(cursorPosition: number): boolean {
|
|
491
515
|
if (
|
|
492
516
|
this.showBashHistorySelector &&
|
|
@@ -506,13 +530,18 @@ export class InputManager {
|
|
|
506
530
|
this.callbacks.onMemoryTypeSelectorStateChange?.(true, message);
|
|
507
531
|
}
|
|
508
532
|
|
|
509
|
-
handleMemoryTypeSelect(type: "project" | "user"): void {
|
|
510
|
-
|
|
511
|
-
|
|
533
|
+
async handleMemoryTypeSelect(type: "project" | "user"): Promise<void> {
|
|
534
|
+
const currentMessage = this.inputText.trim();
|
|
535
|
+
if (currentMessage.startsWith("#")) {
|
|
536
|
+
await this.callbacks.onSaveMemory?.(currentMessage, type);
|
|
537
|
+
}
|
|
538
|
+
// Close the selector
|
|
512
539
|
this.showMemoryTypeSelector = false;
|
|
513
540
|
this.memoryMessage = "";
|
|
514
|
-
|
|
515
541
|
this.callbacks.onMemoryTypeSelectorStateChange?.(false, "");
|
|
542
|
+
|
|
543
|
+
// Clear input box
|
|
544
|
+
this.clearInput();
|
|
516
545
|
}
|
|
517
546
|
|
|
518
547
|
handleCancelMemoryTypeSelect(): void {
|
|
@@ -631,6 +660,29 @@ export class InputManager {
|
|
|
631
660
|
};
|
|
632
661
|
}
|
|
633
662
|
|
|
663
|
+
// Update search queries for active selectors
|
|
664
|
+
private updateSearchQueriesForActiveSelectors(
|
|
665
|
+
inputText: string,
|
|
666
|
+
cursorPosition: number,
|
|
667
|
+
): void {
|
|
668
|
+
if (this.showFileSelector && this.atPosition >= 0) {
|
|
669
|
+
const queryStart = this.atPosition + 1;
|
|
670
|
+
const queryEnd = cursorPosition;
|
|
671
|
+
const newQuery = inputText.substring(queryStart, queryEnd);
|
|
672
|
+
this.updateFileSearchQuery(newQuery);
|
|
673
|
+
} else if (this.showCommandSelector && this.slashPosition >= 0) {
|
|
674
|
+
const queryStart = this.slashPosition + 1;
|
|
675
|
+
const queryEnd = cursorPosition;
|
|
676
|
+
const newQuery = inputText.substring(queryStart, queryEnd);
|
|
677
|
+
this.updateCommandSearchQuery(newQuery);
|
|
678
|
+
} else if (this.showBashHistorySelector && this.exclamationPosition >= 0) {
|
|
679
|
+
const queryStart = this.exclamationPosition + 1;
|
|
680
|
+
const queryEnd = cursorPosition;
|
|
681
|
+
const newQuery = inputText.substring(queryStart, queryEnd);
|
|
682
|
+
this.updateBashHistorySearchQuery(newQuery);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
634
686
|
// Handle special character input that might trigger selectors
|
|
635
687
|
handleSpecialCharInput(char: string): void {
|
|
636
688
|
if (char === "@") {
|
|
@@ -644,25 +696,10 @@ export class InputManager {
|
|
|
644
696
|
// Memory message detection will be handled in submit
|
|
645
697
|
} else {
|
|
646
698
|
// Update search queries for active selectors
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
this.updateFileSearchQuery(newQuery);
|
|
652
|
-
} else if (this.showCommandSelector && this.slashPosition >= 0) {
|
|
653
|
-
const queryStart = this.slashPosition + 1;
|
|
654
|
-
const queryEnd = this.cursorPosition;
|
|
655
|
-
const newQuery = this.inputText.substring(queryStart, queryEnd);
|
|
656
|
-
this.updateCommandSearchQuery(newQuery);
|
|
657
|
-
} else if (
|
|
658
|
-
this.showBashHistorySelector &&
|
|
659
|
-
this.exclamationPosition >= 0
|
|
660
|
-
) {
|
|
661
|
-
const queryStart = this.exclamationPosition + 1;
|
|
662
|
-
const queryEnd = this.cursorPosition;
|
|
663
|
-
const newQuery = this.inputText.substring(queryStart, queryEnd);
|
|
664
|
-
this.updateBashHistorySearchQuery(newQuery);
|
|
665
|
-
}
|
|
699
|
+
this.updateSearchQueriesForActiveSelectors(
|
|
700
|
+
this.inputText,
|
|
701
|
+
this.cursorPosition,
|
|
702
|
+
);
|
|
666
703
|
}
|
|
667
704
|
}
|
|
668
705
|
|
|
@@ -831,6 +868,29 @@ export class InputManager {
|
|
|
831
868
|
this.callbacks.onMcpManagerStateChange?.(show);
|
|
832
869
|
}
|
|
833
870
|
|
|
871
|
+
// Permission mode methods
|
|
872
|
+
getPermissionMode(): PermissionMode {
|
|
873
|
+
return this.permissionMode;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
setPermissionMode(mode: PermissionMode): void {
|
|
877
|
+
this.permissionMode = mode;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
cyclePermissionMode(): void {
|
|
881
|
+
const modes: PermissionMode[] = ["default", "acceptEdits"];
|
|
882
|
+
const currentIndex = modes.indexOf(this.permissionMode);
|
|
883
|
+
const nextIndex =
|
|
884
|
+
currentIndex === -1 ? 0 : (currentIndex + 1) % modes.length;
|
|
885
|
+
const nextMode = modes[nextIndex];
|
|
886
|
+
this.logger?.debug("Cycling permission mode", {
|
|
887
|
+
from: this.permissionMode,
|
|
888
|
+
to: nextMode,
|
|
889
|
+
});
|
|
890
|
+
this.permissionMode = nextMode;
|
|
891
|
+
this.callbacks.onPermissionModeChange?.(this.permissionMode);
|
|
892
|
+
}
|
|
893
|
+
|
|
834
894
|
// Handle submit logic
|
|
835
895
|
async handleSubmit(
|
|
836
896
|
attachedImages: Array<{ id: number; path: string; mimeType: string }>,
|
|
@@ -884,20 +944,26 @@ export class InputManager {
|
|
|
884
944
|
|
|
885
945
|
// Handle selector input (when any selector is active)
|
|
886
946
|
handleSelectorInput(input: string, key: Key): boolean {
|
|
887
|
-
if (key.backspace || key.delete) {
|
|
947
|
+
if (key.backspace || (key.delete && !this.showBashHistorySelector)) {
|
|
888
948
|
if (this.cursorPosition > 0) {
|
|
889
949
|
this.deleteCharAtCursor((newInput, newCursorPosition) => {
|
|
890
950
|
// Check for special character deletion
|
|
891
951
|
this.checkForAtDeletion(newCursorPosition);
|
|
892
952
|
this.checkForSlashDeletion(newCursorPosition);
|
|
893
953
|
this.checkForExclamationDeletion(newCursorPosition);
|
|
954
|
+
|
|
955
|
+
// Update search queries using the same logic as character input
|
|
956
|
+
this.updateSearchQueriesForActiveSelectors(
|
|
957
|
+
newInput,
|
|
958
|
+
newCursorPosition,
|
|
959
|
+
);
|
|
894
960
|
});
|
|
895
961
|
}
|
|
896
962
|
return true;
|
|
897
963
|
}
|
|
898
964
|
|
|
899
|
-
// Arrow keys and
|
|
900
|
-
if (key.upArrow || key.downArrow || key.return) {
|
|
965
|
+
// Arrow keys, Enter and Tab should be handled by selector components
|
|
966
|
+
if (key.upArrow || key.downArrow || key.return || key.tab) {
|
|
901
967
|
// Let selector component handle these keys, but prevent further processing
|
|
902
968
|
// by returning true (indicating we've handled the input)
|
|
903
969
|
return true;
|
|
@@ -909,6 +975,7 @@ export class InputManager {
|
|
|
909
975
|
!("alt" in key && key.alt) &&
|
|
910
976
|
!key.meta &&
|
|
911
977
|
!key.return &&
|
|
978
|
+
!key.tab &&
|
|
912
979
|
!key.escape &&
|
|
913
980
|
!key.leftArrow &&
|
|
914
981
|
!key.rightArrow &&
|
|
@@ -1058,6 +1125,13 @@ export class InputManager {
|
|
|
1058
1125
|
return true;
|
|
1059
1126
|
}
|
|
1060
1127
|
|
|
1128
|
+
// Handle Shift+Tab for permission mode cycling
|
|
1129
|
+
if (key.tab && key.shift) {
|
|
1130
|
+
this.logger?.debug("Shift+Tab detected, cycling permission mode");
|
|
1131
|
+
this.cyclePermissionMode();
|
|
1132
|
+
return true;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1061
1135
|
// Check if any selector is active
|
|
1062
1136
|
if (
|
|
1063
1137
|
this.showFileSelector ||
|
package/src/print-cli.ts
CHANGED
|
@@ -1,15 +1,37 @@
|
|
|
1
1
|
import { Agent, AgentCallbacks } from "wave-agent-sdk";
|
|
2
|
-
import { logger } from "./utils/logger.js";
|
|
3
2
|
import { displayUsageSummary } from "./utils/usageSummary.js";
|
|
4
3
|
|
|
5
4
|
export interface PrintCliOptions {
|
|
6
5
|
restoreSessionId?: string;
|
|
7
6
|
continueLastSession?: boolean;
|
|
8
7
|
message?: string;
|
|
8
|
+
showStats?: boolean;
|
|
9
|
+
bypassPermissions?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function displayTimingInfo(startTime: Date, showStats: boolean): void {
|
|
13
|
+
// Skip timing info in test environment or if stats are disabled
|
|
14
|
+
if (process.env.NODE_ENV === "test" || process.env.VITEST || !showStats) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const endTime = new Date();
|
|
19
|
+
const duration = endTime.getTime() - startTime.getTime();
|
|
20
|
+
|
|
21
|
+
process.stdout.write(`\n\n📅 Start time: ${startTime.toISOString()}\n`);
|
|
22
|
+
process.stdout.write(`📅 End time: ${endTime.toISOString()}\n`);
|
|
23
|
+
process.stdout.write(`⏱️ Duration: ${duration}ms\n`);
|
|
9
24
|
}
|
|
10
25
|
|
|
11
26
|
export async function startPrintCli(options: PrintCliOptions): Promise<void> {
|
|
12
|
-
const
|
|
27
|
+
const startTime = new Date();
|
|
28
|
+
const {
|
|
29
|
+
restoreSessionId,
|
|
30
|
+
continueLastSession,
|
|
31
|
+
message,
|
|
32
|
+
showStats = false,
|
|
33
|
+
bypassPermissions,
|
|
34
|
+
} = options;
|
|
13
35
|
|
|
14
36
|
if (
|
|
15
37
|
(!message || message.trim() === "") &&
|
|
@@ -23,14 +45,102 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
|
|
|
23
45
|
}
|
|
24
46
|
|
|
25
47
|
let agent: Agent;
|
|
48
|
+
let isReasoning = false;
|
|
49
|
+
let isContent = false;
|
|
50
|
+
const subagentReasoningStates = new Map<string, boolean>();
|
|
51
|
+
const subagentContentStates = new Map<string, boolean>();
|
|
26
52
|
|
|
27
53
|
// Setup callbacks for agent
|
|
28
54
|
const callbacks: AgentCallbacks = {
|
|
29
|
-
onAssistantMessageAdded: (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
55
|
+
onAssistantMessageAdded: () => {
|
|
56
|
+
isReasoning = false;
|
|
57
|
+
isContent = false;
|
|
58
|
+
// Assistant message started - no content to output yet
|
|
59
|
+
process.stdout.write("\n");
|
|
60
|
+
},
|
|
61
|
+
onAssistantReasoningUpdated: (chunk: string) => {
|
|
62
|
+
if (!isReasoning) {
|
|
63
|
+
process.stdout.write("💭 Reasoning:\n");
|
|
64
|
+
isReasoning = true;
|
|
65
|
+
}
|
|
66
|
+
process.stdout.write(chunk);
|
|
67
|
+
},
|
|
68
|
+
onAssistantContentUpdated: (chunk: string) => {
|
|
69
|
+
if (isReasoning && !isContent) {
|
|
70
|
+
process.stdout.write("\n\n📝 Response:\n");
|
|
71
|
+
isContent = true;
|
|
72
|
+
}
|
|
73
|
+
// FR-001: Stream content updates for real-time display - output only the new chunk
|
|
74
|
+
process.stdout.write(chunk);
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
// Tool block callback - display tool name when tool starts
|
|
78
|
+
onToolBlockUpdated: (params) => {
|
|
79
|
+
// Print tool name only during 'running' stage (happens once per tool call)
|
|
80
|
+
if (params.stage === "running" && params.name) {
|
|
81
|
+
process.stdout.write(`\n🔧 ${params.name}`);
|
|
82
|
+
if (params.compactParams) {
|
|
83
|
+
process.stdout.write(` ${params.compactParams}`);
|
|
84
|
+
}
|
|
85
|
+
process.stdout.write(`\n`);
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
// Subagent block callbacks
|
|
90
|
+
onSubAgentBlockAdded: (subagentId: string, parameters) => {
|
|
91
|
+
// Display subagent creation with indentation
|
|
92
|
+
process.stdout.write(
|
|
93
|
+
`\n🤖 Subagent [${parameters.subagent_type}]: ${parameters.description}\n`,
|
|
94
|
+
);
|
|
95
|
+
},
|
|
96
|
+
onSubAgentBlockUpdated: (subagentId: string, status) => {
|
|
97
|
+
// Display subagent status updates
|
|
98
|
+
const statusIconMap = {
|
|
99
|
+
active: "🔄",
|
|
100
|
+
completed: "✅",
|
|
101
|
+
error: "❌",
|
|
102
|
+
aborted: "⚠️",
|
|
103
|
+
} as const;
|
|
104
|
+
|
|
105
|
+
const statusIcon = statusIconMap[status] ?? "🔄";
|
|
106
|
+
process.stdout.write(` ${statusIcon} Subagent status: ${status}\n`);
|
|
107
|
+
},
|
|
108
|
+
// Subagent message callbacks
|
|
109
|
+
onSubagentAssistantMessageAdded: (subagentId: string) => {
|
|
110
|
+
subagentReasoningStates.set(subagentId, false);
|
|
111
|
+
subagentContentStates.set(subagentId, false);
|
|
112
|
+
// Subagent assistant message started - add indentation
|
|
113
|
+
process.stdout.write("\n ");
|
|
114
|
+
},
|
|
115
|
+
onSubagentAssistantReasoningUpdated: (
|
|
116
|
+
subagentId: string,
|
|
117
|
+
chunk: string,
|
|
118
|
+
) => {
|
|
119
|
+
if (!subagentReasoningStates.get(subagentId)) {
|
|
120
|
+
process.stdout.write("💭 Reasoning: ");
|
|
121
|
+
subagentReasoningStates.set(subagentId, true);
|
|
122
|
+
}
|
|
123
|
+
process.stdout.write(chunk);
|
|
124
|
+
},
|
|
125
|
+
onSubagentAssistantContentUpdated: (subagentId: string, chunk: string) => {
|
|
126
|
+
if (
|
|
127
|
+
subagentReasoningStates.get(subagentId) &&
|
|
128
|
+
!subagentContentStates.get(subagentId)
|
|
129
|
+
) {
|
|
130
|
+
process.stdout.write("\n 📝 Response: ");
|
|
131
|
+
subagentContentStates.set(subagentId, true);
|
|
33
132
|
}
|
|
133
|
+
// Stream subagent content with indentation - output only the new chunk
|
|
134
|
+
process.stdout.write(chunk);
|
|
135
|
+
},
|
|
136
|
+
onSubagentUserMessageAdded: (_subagentId: string, params) => {
|
|
137
|
+
// Display subagent user messages with indentation
|
|
138
|
+
process.stdout.write(`\n 👤 User: ${params.content}\n`);
|
|
139
|
+
},
|
|
140
|
+
// Error block callback
|
|
141
|
+
onErrorBlockAdded: (error: string) => {
|
|
142
|
+
// Display error blocks with distinct formatting
|
|
143
|
+
process.stdout.write(`\n❌ Error: ${error}\n`);
|
|
34
144
|
},
|
|
35
145
|
};
|
|
36
146
|
|
|
@@ -40,7 +150,8 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
|
|
|
40
150
|
callbacks,
|
|
41
151
|
restoreSessionId,
|
|
42
152
|
continueLastSession,
|
|
43
|
-
|
|
153
|
+
permissionMode: bypassPermissions ? "bypassPermissions" : undefined,
|
|
154
|
+
// 保持流式模式以获得更好的命令行用户体验
|
|
44
155
|
});
|
|
45
156
|
|
|
46
157
|
// Send message if provided and not empty
|
|
@@ -49,29 +160,40 @@ export async function startPrintCli(options: PrintCliOptions): Promise<void> {
|
|
|
49
160
|
}
|
|
50
161
|
|
|
51
162
|
// Display usage summary before exit
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
163
|
+
if (showStats) {
|
|
164
|
+
try {
|
|
165
|
+
const usages = agent.usages;
|
|
166
|
+
const sessionFilePath = agent.sessionFilePath;
|
|
167
|
+
displayUsageSummary(usages, sessionFilePath);
|
|
168
|
+
} catch {
|
|
169
|
+
// Silently ignore usage summary errors
|
|
170
|
+
}
|
|
58
171
|
}
|
|
59
172
|
|
|
173
|
+
// Display timing information
|
|
174
|
+
displayTimingInfo(startTime, showStats);
|
|
175
|
+
|
|
60
176
|
// Destroy agent and exit after sendMessage completes
|
|
61
|
-
agent.destroy();
|
|
177
|
+
await agent.destroy();
|
|
62
178
|
process.exit(0);
|
|
63
179
|
} catch (error) {
|
|
64
180
|
console.error("Failed to send message:", error);
|
|
65
181
|
if (agent!) {
|
|
66
182
|
// Display usage summary even on error
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
183
|
+
if (showStats) {
|
|
184
|
+
try {
|
|
185
|
+
const usages = agent.usages;
|
|
186
|
+
const sessionFilePath = agent.sessionFilePath;
|
|
187
|
+
displayUsageSummary(usages, sessionFilePath);
|
|
188
|
+
} catch {
|
|
189
|
+
// Silently ignore usage summary errors
|
|
190
|
+
}
|
|
73
191
|
}
|
|
74
|
-
|
|
192
|
+
|
|
193
|
+
// Display timing information even on error
|
|
194
|
+
displayTimingInfo(startTime, showStats);
|
|
195
|
+
|
|
196
|
+
await agent.destroy();
|
|
75
197
|
}
|
|
76
198
|
process.exit(1);
|
|
77
199
|
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool parameter transformation utilities for UI rendering
|
|
3
|
+
* Forces type judgment based on tool name using type assertions
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
type Change,
|
|
8
|
+
type WriteToolParameters,
|
|
9
|
+
type EditToolParameters,
|
|
10
|
+
type MultiEditToolParameters,
|
|
11
|
+
} from "wave-agent-sdk";
|
|
12
|
+
import { logger } from "./logger.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parse tool block parameters
|
|
16
|
+
*/
|
|
17
|
+
function parseToolParameters(parameters: string): unknown {
|
|
18
|
+
if (!parameters) {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(parameters);
|
|
24
|
+
} catch (error) {
|
|
25
|
+
logger.warn("Failed to parse tool parameters:", error);
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Transform Write tool parameters to changes
|
|
32
|
+
*/
|
|
33
|
+
export function transformWriteParameters(
|
|
34
|
+
parameters: WriteToolParameters,
|
|
35
|
+
): Change[] {
|
|
36
|
+
return [
|
|
37
|
+
{
|
|
38
|
+
oldContent: "", // No previous content for write operations
|
|
39
|
+
newContent: parameters.content,
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Transform Edit tool parameters to changes
|
|
46
|
+
*/
|
|
47
|
+
export function transformEditParameters(
|
|
48
|
+
parameters: EditToolParameters,
|
|
49
|
+
): Change[] {
|
|
50
|
+
return [
|
|
51
|
+
{
|
|
52
|
+
oldContent: parameters.old_string,
|
|
53
|
+
newContent: parameters.new_string,
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Transform MultiEdit tool parameters to changes
|
|
60
|
+
*/
|
|
61
|
+
export function transformMultiEditParameters(
|
|
62
|
+
parameters: MultiEditToolParameters,
|
|
63
|
+
): Change[] {
|
|
64
|
+
return parameters.edits.map((edit) => ({
|
|
65
|
+
oldContent: edit.old_string,
|
|
66
|
+
newContent: edit.new_string,
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Transform tool block parameters into standardized Change[] array for diff display
|
|
72
|
+
* Forces type judgment based on tool name using type assertions
|
|
73
|
+
*/
|
|
74
|
+
export function transformToolBlockToChanges(
|
|
75
|
+
toolName: string,
|
|
76
|
+
parameters: string,
|
|
77
|
+
): Change[] {
|
|
78
|
+
try {
|
|
79
|
+
if (!toolName) {
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const parsedParams = parseToolParameters(parameters);
|
|
84
|
+
|
|
85
|
+
switch (toolName) {
|
|
86
|
+
case "Write":
|
|
87
|
+
return transformWriteParameters(parsedParams as WriteToolParameters);
|
|
88
|
+
|
|
89
|
+
case "Edit":
|
|
90
|
+
return transformEditParameters(parsedParams as EditToolParameters);
|
|
91
|
+
|
|
92
|
+
case "MultiEdit":
|
|
93
|
+
return transformMultiEditParameters(
|
|
94
|
+
parsedParams as MultiEditToolParameters,
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
default:
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
} catch (error) {
|
|
101
|
+
logger.warn("Failed to transform tool block to changes:", error);
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -12,6 +12,13 @@ export interface TokenSummary {
|
|
|
12
12
|
agent_calls: number;
|
|
13
13
|
compressions: number;
|
|
14
14
|
};
|
|
15
|
+
// Cache-related tokens (for Claude models)
|
|
16
|
+
cache_read_input_tokens?: number;
|
|
17
|
+
cache_creation_input_tokens?: number;
|
|
18
|
+
cache_creation?: {
|
|
19
|
+
ephemeral_5m_input_tokens: number;
|
|
20
|
+
ephemeral_1h_input_tokens: number;
|
|
21
|
+
};
|
|
15
22
|
}
|
|
16
23
|
|
|
17
24
|
/**
|
|
@@ -45,6 +52,36 @@ export function calculateTokenSummary(
|
|
|
45
52
|
summary.completion_tokens += usage.completion_tokens;
|
|
46
53
|
summary.total_tokens += usage.total_tokens;
|
|
47
54
|
|
|
55
|
+
// Handle cache tokens if present and non-zero
|
|
56
|
+
if (usage.cache_read_input_tokens && usage.cache_read_input_tokens > 0) {
|
|
57
|
+
summary.cache_read_input_tokens =
|
|
58
|
+
(summary.cache_read_input_tokens || 0) + usage.cache_read_input_tokens;
|
|
59
|
+
}
|
|
60
|
+
if (
|
|
61
|
+
usage.cache_creation_input_tokens &&
|
|
62
|
+
usage.cache_creation_input_tokens > 0
|
|
63
|
+
) {
|
|
64
|
+
summary.cache_creation_input_tokens =
|
|
65
|
+
(summary.cache_creation_input_tokens || 0) +
|
|
66
|
+
usage.cache_creation_input_tokens;
|
|
67
|
+
}
|
|
68
|
+
if (
|
|
69
|
+
usage.cache_creation &&
|
|
70
|
+
(usage.cache_creation.ephemeral_5m_input_tokens > 0 ||
|
|
71
|
+
usage.cache_creation.ephemeral_1h_input_tokens > 0)
|
|
72
|
+
) {
|
|
73
|
+
if (!summary.cache_creation) {
|
|
74
|
+
summary.cache_creation = {
|
|
75
|
+
ephemeral_5m_input_tokens: 0,
|
|
76
|
+
ephemeral_1h_input_tokens: 0,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
summary.cache_creation.ephemeral_5m_input_tokens +=
|
|
80
|
+
usage.cache_creation.ephemeral_5m_input_tokens || 0;
|
|
81
|
+
summary.cache_creation.ephemeral_1h_input_tokens +=
|
|
82
|
+
usage.cache_creation.ephemeral_1h_input_tokens || 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
48
85
|
// Track operation types
|
|
49
86
|
if (usage.operation_type === "agent") {
|
|
50
87
|
summary.operations.agent_calls += 1;
|
|
@@ -93,6 +130,11 @@ export function displayUsageSummary(
|
|
|
93
130
|
let totalTokens = 0;
|
|
94
131
|
let totalAgentCalls = 0;
|
|
95
132
|
let totalCompressions = 0;
|
|
133
|
+
let totalCacheRead = 0;
|
|
134
|
+
let totalCacheCreation = 0;
|
|
135
|
+
let totalCache5m = 0;
|
|
136
|
+
let totalCache1h = 0;
|
|
137
|
+
let hasCacheData = false;
|
|
96
138
|
|
|
97
139
|
for (const [, summary] of Object.entries(summaries)) {
|
|
98
140
|
console.log(`Model: ${summary.model}`);
|
|
@@ -101,6 +143,52 @@ export function displayUsageSummary(
|
|
|
101
143
|
` Completion tokens: ${summary.completion_tokens.toLocaleString()}`,
|
|
102
144
|
);
|
|
103
145
|
console.log(` Total tokens: ${summary.total_tokens.toLocaleString()}`);
|
|
146
|
+
|
|
147
|
+
// Display cache information if available
|
|
148
|
+
if (
|
|
149
|
+
summary.cache_read_input_tokens ||
|
|
150
|
+
summary.cache_creation_input_tokens ||
|
|
151
|
+
summary.cache_creation
|
|
152
|
+
) {
|
|
153
|
+
hasCacheData = true;
|
|
154
|
+
console.log(" Cache Usage:");
|
|
155
|
+
|
|
156
|
+
if (
|
|
157
|
+
summary.cache_read_input_tokens &&
|
|
158
|
+
summary.cache_read_input_tokens > 0
|
|
159
|
+
) {
|
|
160
|
+
console.log(
|
|
161
|
+
` Read from cache: ${summary.cache_read_input_tokens.toLocaleString()} tokens`,
|
|
162
|
+
);
|
|
163
|
+
totalCacheRead += summary.cache_read_input_tokens;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (
|
|
167
|
+
summary.cache_creation_input_tokens &&
|
|
168
|
+
summary.cache_creation_input_tokens > 0
|
|
169
|
+
) {
|
|
170
|
+
console.log(
|
|
171
|
+
` Created cache: ${summary.cache_creation_input_tokens.toLocaleString()} tokens`,
|
|
172
|
+
);
|
|
173
|
+
totalCacheCreation += summary.cache_creation_input_tokens;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (summary.cache_creation) {
|
|
177
|
+
if (summary.cache_creation.ephemeral_5m_input_tokens > 0) {
|
|
178
|
+
console.log(
|
|
179
|
+
` 5m cache: ${summary.cache_creation.ephemeral_5m_input_tokens.toLocaleString()} tokens`,
|
|
180
|
+
);
|
|
181
|
+
totalCache5m += summary.cache_creation.ephemeral_5m_input_tokens;
|
|
182
|
+
}
|
|
183
|
+
if (summary.cache_creation.ephemeral_1h_input_tokens > 0) {
|
|
184
|
+
console.log(
|
|
185
|
+
` 1h cache: ${summary.cache_creation.ephemeral_1h_input_tokens.toLocaleString()} tokens`,
|
|
186
|
+
);
|
|
187
|
+
totalCache1h += summary.cache_creation.ephemeral_1h_input_tokens;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
104
192
|
console.log(
|
|
105
193
|
` Operations: ${summary.operations.agent_calls} agent calls, ${summary.operations.compressions} compressions`,
|
|
106
194
|
);
|
|
@@ -118,6 +206,27 @@ export function displayUsageSummary(
|
|
|
118
206
|
console.log(` Prompt tokens: ${totalPrompt.toLocaleString()}`);
|
|
119
207
|
console.log(` Completion tokens: ${totalCompletion.toLocaleString()}`);
|
|
120
208
|
console.log(` Total tokens: ${totalTokens.toLocaleString()}`);
|
|
209
|
+
|
|
210
|
+
if (hasCacheData) {
|
|
211
|
+
console.log(" Cache Usage:");
|
|
212
|
+
if (totalCacheRead > 0) {
|
|
213
|
+
console.log(
|
|
214
|
+
` Read from cache: ${totalCacheRead.toLocaleString()} tokens`,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
if (totalCacheCreation > 0) {
|
|
218
|
+
console.log(
|
|
219
|
+
` Created cache: ${totalCacheCreation.toLocaleString()} tokens`,
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
if (totalCache5m > 0) {
|
|
223
|
+
console.log(` 5m cache: ${totalCache5m.toLocaleString()} tokens`);
|
|
224
|
+
}
|
|
225
|
+
if (totalCache1h > 0) {
|
|
226
|
+
console.log(` 1h cache: ${totalCache1h.toLocaleString()} tokens`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
121
230
|
console.log(
|
|
122
231
|
` Operations: ${totalAgentCalls} agent calls, ${totalCompressions} compressions`,
|
|
123
232
|
);
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { DiffBlock } from "wave-agent-sdk";
|
|
3
|
-
interface DiffViewerProps {
|
|
4
|
-
block: DiffBlock;
|
|
5
|
-
isExpanded?: boolean;
|
|
6
|
-
}
|
|
7
|
-
export declare const DiffViewer: React.FC<DiffViewerProps>;
|
|
8
|
-
export {};
|
|
9
|
-
//# sourceMappingURL=DiffViewer.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DiffViewer.d.ts","sourceRoot":"","sources":["../../src/components/DiffViewer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,UAAU,eAAe;IACvB,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAwCD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAgRhD,CAAC"}
|