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,4 +1,4 @@
|
|
|
1
|
-
import { searchFiles as searchFilesUtil } from "
|
|
1
|
+
import { searchFiles as searchFilesUtil, } from "wave-agent-sdk";
|
|
2
2
|
import { readClipboardImage } from "../utils/clipboard.js";
|
|
3
3
|
export class InputManager {
|
|
4
4
|
constructor(callbacks = {}) {
|
|
@@ -40,13 +40,19 @@ export class InputManager {
|
|
|
40
40
|
// Additional UI state
|
|
41
41
|
this.showBashManager = false;
|
|
42
42
|
this.showMcpManager = false;
|
|
43
|
+
// Permission mode state
|
|
44
|
+
this.permissionMode = "default";
|
|
43
45
|
// Flag to prevent handleInput conflicts when selector selection occurs
|
|
44
46
|
this.selectorJustUsed = false;
|
|
45
47
|
this.callbacks = callbacks;
|
|
48
|
+
this.logger = callbacks.logger;
|
|
46
49
|
}
|
|
47
50
|
// Update callbacks
|
|
48
51
|
updateCallbacks(callbacks) {
|
|
49
52
|
this.callbacks = { ...this.callbacks, ...callbacks };
|
|
53
|
+
if (callbacks.logger) {
|
|
54
|
+
this.logger = callbacks.logger;
|
|
55
|
+
}
|
|
50
56
|
}
|
|
51
57
|
// Core input methods
|
|
52
58
|
getInputText() {
|
|
@@ -313,6 +319,15 @@ export class InputManager {
|
|
|
313
319
|
this.callbacks.onBashHistorySelectorStateChange?.(false, "", -1);
|
|
314
320
|
return command; // Return command to execute
|
|
315
321
|
}
|
|
322
|
+
handleBashHistoryExecuteAndSend(command) {
|
|
323
|
+
const commandToExecute = this.handleBashHistoryExecute(command);
|
|
324
|
+
// Clear input box and execute command, ensure command starts with !
|
|
325
|
+
const bashCommand = commandToExecute.startsWith("!")
|
|
326
|
+
? commandToExecute
|
|
327
|
+
: `!${commandToExecute}`;
|
|
328
|
+
this.clearInput();
|
|
329
|
+
this.callbacks.onSendMessage?.(bashCommand);
|
|
330
|
+
}
|
|
316
331
|
checkForExclamationDeletion(cursorPosition) {
|
|
317
332
|
if (this.showBashHistorySelector &&
|
|
318
333
|
cursorPosition <= this.exclamationPosition) {
|
|
@@ -327,12 +342,17 @@ export class InputManager {
|
|
|
327
342
|
this.memoryMessage = message;
|
|
328
343
|
this.callbacks.onMemoryTypeSelectorStateChange?.(true, message);
|
|
329
344
|
}
|
|
330
|
-
handleMemoryTypeSelect(type) {
|
|
331
|
-
|
|
332
|
-
|
|
345
|
+
async handleMemoryTypeSelect(type) {
|
|
346
|
+
const currentMessage = this.inputText.trim();
|
|
347
|
+
if (currentMessage.startsWith("#")) {
|
|
348
|
+
await this.callbacks.onSaveMemory?.(currentMessage, type);
|
|
349
|
+
}
|
|
350
|
+
// Close the selector
|
|
333
351
|
this.showMemoryTypeSelector = false;
|
|
334
352
|
this.memoryMessage = "";
|
|
335
353
|
this.callbacks.onMemoryTypeSelectorStateChange?.(false, "");
|
|
354
|
+
// Clear input box
|
|
355
|
+
this.clearInput();
|
|
336
356
|
}
|
|
337
357
|
handleCancelMemoryTypeSelect() {
|
|
338
358
|
this.showMemoryTypeSelector = false;
|
|
@@ -430,6 +450,27 @@ export class InputManager {
|
|
|
430
450
|
message: this.memoryMessage,
|
|
431
451
|
};
|
|
432
452
|
}
|
|
453
|
+
// Update search queries for active selectors
|
|
454
|
+
updateSearchQueriesForActiveSelectors(inputText, cursorPosition) {
|
|
455
|
+
if (this.showFileSelector && this.atPosition >= 0) {
|
|
456
|
+
const queryStart = this.atPosition + 1;
|
|
457
|
+
const queryEnd = cursorPosition;
|
|
458
|
+
const newQuery = inputText.substring(queryStart, queryEnd);
|
|
459
|
+
this.updateFileSearchQuery(newQuery);
|
|
460
|
+
}
|
|
461
|
+
else if (this.showCommandSelector && this.slashPosition >= 0) {
|
|
462
|
+
const queryStart = this.slashPosition + 1;
|
|
463
|
+
const queryEnd = cursorPosition;
|
|
464
|
+
const newQuery = inputText.substring(queryStart, queryEnd);
|
|
465
|
+
this.updateCommandSearchQuery(newQuery);
|
|
466
|
+
}
|
|
467
|
+
else if (this.showBashHistorySelector && this.exclamationPosition >= 0) {
|
|
468
|
+
const queryStart = this.exclamationPosition + 1;
|
|
469
|
+
const queryEnd = cursorPosition;
|
|
470
|
+
const newQuery = inputText.substring(queryStart, queryEnd);
|
|
471
|
+
this.updateBashHistorySearchQuery(newQuery);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
433
474
|
// Handle special character input that might trigger selectors
|
|
434
475
|
handleSpecialCharInput(char) {
|
|
435
476
|
if (char === "@") {
|
|
@@ -447,25 +488,7 @@ export class InputManager {
|
|
|
447
488
|
}
|
|
448
489
|
else {
|
|
449
490
|
// Update search queries for active selectors
|
|
450
|
-
|
|
451
|
-
const queryStart = this.atPosition + 1;
|
|
452
|
-
const queryEnd = this.cursorPosition;
|
|
453
|
-
const newQuery = this.inputText.substring(queryStart, queryEnd);
|
|
454
|
-
this.updateFileSearchQuery(newQuery);
|
|
455
|
-
}
|
|
456
|
-
else if (this.showCommandSelector && this.slashPosition >= 0) {
|
|
457
|
-
const queryStart = this.slashPosition + 1;
|
|
458
|
-
const queryEnd = this.cursorPosition;
|
|
459
|
-
const newQuery = this.inputText.substring(queryStart, queryEnd);
|
|
460
|
-
this.updateCommandSearchQuery(newQuery);
|
|
461
|
-
}
|
|
462
|
-
else if (this.showBashHistorySelector &&
|
|
463
|
-
this.exclamationPosition >= 0) {
|
|
464
|
-
const queryStart = this.exclamationPosition + 1;
|
|
465
|
-
const queryEnd = this.cursorPosition;
|
|
466
|
-
const newQuery = this.inputText.substring(queryStart, queryEnd);
|
|
467
|
-
this.updateBashHistorySearchQuery(newQuery);
|
|
468
|
-
}
|
|
491
|
+
this.updateSearchQueriesForActiveSelectors(this.inputText, this.cursorPosition);
|
|
469
492
|
}
|
|
470
493
|
}
|
|
471
494
|
// Long text compression methods
|
|
@@ -602,6 +625,25 @@ export class InputManager {
|
|
|
602
625
|
this.showMcpManager = show;
|
|
603
626
|
this.callbacks.onMcpManagerStateChange?.(show);
|
|
604
627
|
}
|
|
628
|
+
// Permission mode methods
|
|
629
|
+
getPermissionMode() {
|
|
630
|
+
return this.permissionMode;
|
|
631
|
+
}
|
|
632
|
+
setPermissionMode(mode) {
|
|
633
|
+
this.permissionMode = mode;
|
|
634
|
+
}
|
|
635
|
+
cyclePermissionMode() {
|
|
636
|
+
const modes = ["default", "acceptEdits"];
|
|
637
|
+
const currentIndex = modes.indexOf(this.permissionMode);
|
|
638
|
+
const nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % modes.length;
|
|
639
|
+
const nextMode = modes[nextIndex];
|
|
640
|
+
this.logger?.debug("Cycling permission mode", {
|
|
641
|
+
from: this.permissionMode,
|
|
642
|
+
to: nextMode,
|
|
643
|
+
});
|
|
644
|
+
this.permissionMode = nextMode;
|
|
645
|
+
this.callbacks.onPermissionModeChange?.(this.permissionMode);
|
|
646
|
+
}
|
|
605
647
|
// Handle submit logic
|
|
606
648
|
async handleSubmit(attachedImages, isLoading = false, isCommandRunning = false) {
|
|
607
649
|
// Prevent submission during loading or command execution
|
|
@@ -638,19 +680,21 @@ export class InputManager {
|
|
|
638
680
|
}
|
|
639
681
|
// Handle selector input (when any selector is active)
|
|
640
682
|
handleSelectorInput(input, key) {
|
|
641
|
-
if (key.backspace || key.delete) {
|
|
683
|
+
if (key.backspace || (key.delete && !this.showBashHistorySelector)) {
|
|
642
684
|
if (this.cursorPosition > 0) {
|
|
643
685
|
this.deleteCharAtCursor((newInput, newCursorPosition) => {
|
|
644
686
|
// Check for special character deletion
|
|
645
687
|
this.checkForAtDeletion(newCursorPosition);
|
|
646
688
|
this.checkForSlashDeletion(newCursorPosition);
|
|
647
689
|
this.checkForExclamationDeletion(newCursorPosition);
|
|
690
|
+
// Update search queries using the same logic as character input
|
|
691
|
+
this.updateSearchQueriesForActiveSelectors(newInput, newCursorPosition);
|
|
648
692
|
});
|
|
649
693
|
}
|
|
650
694
|
return true;
|
|
651
695
|
}
|
|
652
|
-
// Arrow keys and
|
|
653
|
-
if (key.upArrow || key.downArrow || key.return) {
|
|
696
|
+
// Arrow keys, Enter and Tab should be handled by selector components
|
|
697
|
+
if (key.upArrow || key.downArrow || key.return || key.tab) {
|
|
654
698
|
// Let selector component handle these keys, but prevent further processing
|
|
655
699
|
// by returning true (indicating we've handled the input)
|
|
656
700
|
return true;
|
|
@@ -660,6 +704,7 @@ export class InputManager {
|
|
|
660
704
|
!("alt" in key && key.alt) &&
|
|
661
705
|
!key.meta &&
|
|
662
706
|
!key.return &&
|
|
707
|
+
!key.tab &&
|
|
663
708
|
!key.escape &&
|
|
664
709
|
!key.leftArrow &&
|
|
665
710
|
!key.rightArrow &&
|
|
@@ -773,6 +818,12 @@ export class InputManager {
|
|
|
773
818
|
this.callbacks.onAbortMessage?.();
|
|
774
819
|
return true;
|
|
775
820
|
}
|
|
821
|
+
// Handle Shift+Tab for permission mode cycling
|
|
822
|
+
if (key.tab && key.shift) {
|
|
823
|
+
this.logger?.debug("Shift+Tab detected, cycling permission mode");
|
|
824
|
+
this.cyclePermissionMode();
|
|
825
|
+
return true;
|
|
826
|
+
}
|
|
776
827
|
// Check if any selector is active
|
|
777
828
|
if (this.showFileSelector ||
|
|
778
829
|
this.showCommandSelector ||
|
package/dist/print-cli.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ export interface PrintCliOptions {
|
|
|
2
2
|
restoreSessionId?: string;
|
|
3
3
|
continueLastSession?: boolean;
|
|
4
4
|
message?: string;
|
|
5
|
+
showStats?: boolean;
|
|
6
|
+
bypassPermissions?: boolean;
|
|
5
7
|
}
|
|
6
8
|
export declare function startPrintCli(options: PrintCliOptions): Promise<void>;
|
|
7
9
|
//# sourceMappingURL=print-cli.d.ts.map
|
package/dist/print-cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print-cli.d.ts","sourceRoot":"","sources":["../src/print-cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"print-cli.d.ts","sourceRoot":"","sources":["../src/print-cli.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAgBD,wBAAsB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA8K3E"}
|
package/dist/print-cli.js
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { Agent } from "wave-agent-sdk";
|
|
2
|
-
import { logger } from "./utils/logger.js";
|
|
3
2
|
import { displayUsageSummary } from "./utils/usageSummary.js";
|
|
3
|
+
function displayTimingInfo(startTime, showStats) {
|
|
4
|
+
// Skip timing info in test environment or if stats are disabled
|
|
5
|
+
if (process.env.NODE_ENV === "test" || process.env.VITEST || !showStats) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const endTime = new Date();
|
|
9
|
+
const duration = endTime.getTime() - startTime.getTime();
|
|
10
|
+
process.stdout.write(`\n\n📅 Start time: ${startTime.toISOString()}\n`);
|
|
11
|
+
process.stdout.write(`📅 End time: ${endTime.toISOString()}\n`);
|
|
12
|
+
process.stdout.write(`⏱️ Duration: ${duration}ms\n`);
|
|
13
|
+
}
|
|
4
14
|
export async function startPrintCli(options) {
|
|
5
|
-
const
|
|
15
|
+
const startTime = new Date();
|
|
16
|
+
const { restoreSessionId, continueLastSession, message, showStats = false, bypassPermissions, } = options;
|
|
6
17
|
if ((!message || message.trim() === "") &&
|
|
7
18
|
!continueLastSession &&
|
|
8
19
|
!restoreSessionId) {
|
|
@@ -10,13 +21,91 @@ export async function startPrintCli(options) {
|
|
|
10
21
|
process.exit(1);
|
|
11
22
|
}
|
|
12
23
|
let agent;
|
|
24
|
+
let isReasoning = false;
|
|
25
|
+
let isContent = false;
|
|
26
|
+
const subagentReasoningStates = new Map();
|
|
27
|
+
const subagentContentStates = new Map();
|
|
13
28
|
// Setup callbacks for agent
|
|
14
29
|
const callbacks = {
|
|
15
|
-
onAssistantMessageAdded: (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
30
|
+
onAssistantMessageAdded: () => {
|
|
31
|
+
isReasoning = false;
|
|
32
|
+
isContent = false;
|
|
33
|
+
// Assistant message started - no content to output yet
|
|
34
|
+
process.stdout.write("\n");
|
|
35
|
+
},
|
|
36
|
+
onAssistantReasoningUpdated: (chunk) => {
|
|
37
|
+
if (!isReasoning) {
|
|
38
|
+
process.stdout.write("💭 Reasoning:\n");
|
|
39
|
+
isReasoning = true;
|
|
40
|
+
}
|
|
41
|
+
process.stdout.write(chunk);
|
|
42
|
+
},
|
|
43
|
+
onAssistantContentUpdated: (chunk) => {
|
|
44
|
+
if (isReasoning && !isContent) {
|
|
45
|
+
process.stdout.write("\n\n📝 Response:\n");
|
|
46
|
+
isContent = true;
|
|
47
|
+
}
|
|
48
|
+
// FR-001: Stream content updates for real-time display - output only the new chunk
|
|
49
|
+
process.stdout.write(chunk);
|
|
50
|
+
},
|
|
51
|
+
// Tool block callback - display tool name when tool starts
|
|
52
|
+
onToolBlockUpdated: (params) => {
|
|
53
|
+
// Print tool name only during 'running' stage (happens once per tool call)
|
|
54
|
+
if (params.stage === "running" && params.name) {
|
|
55
|
+
process.stdout.write(`\n🔧 ${params.name}`);
|
|
56
|
+
if (params.compactParams) {
|
|
57
|
+
process.stdout.write(` ${params.compactParams}`);
|
|
58
|
+
}
|
|
59
|
+
process.stdout.write(`\n`);
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
// Subagent block callbacks
|
|
63
|
+
onSubAgentBlockAdded: (subagentId, parameters) => {
|
|
64
|
+
// Display subagent creation with indentation
|
|
65
|
+
process.stdout.write(`\n🤖 Subagent [${parameters.subagent_type}]: ${parameters.description}\n`);
|
|
66
|
+
},
|
|
67
|
+
onSubAgentBlockUpdated: (subagentId, status) => {
|
|
68
|
+
// Display subagent status updates
|
|
69
|
+
const statusIconMap = {
|
|
70
|
+
active: "🔄",
|
|
71
|
+
completed: "✅",
|
|
72
|
+
error: "❌",
|
|
73
|
+
aborted: "⚠️",
|
|
74
|
+
};
|
|
75
|
+
const statusIcon = statusIconMap[status] ?? "🔄";
|
|
76
|
+
process.stdout.write(` ${statusIcon} Subagent status: ${status}\n`);
|
|
77
|
+
},
|
|
78
|
+
// Subagent message callbacks
|
|
79
|
+
onSubagentAssistantMessageAdded: (subagentId) => {
|
|
80
|
+
subagentReasoningStates.set(subagentId, false);
|
|
81
|
+
subagentContentStates.set(subagentId, false);
|
|
82
|
+
// Subagent assistant message started - add indentation
|
|
83
|
+
process.stdout.write("\n ");
|
|
84
|
+
},
|
|
85
|
+
onSubagentAssistantReasoningUpdated: (subagentId, chunk) => {
|
|
86
|
+
if (!subagentReasoningStates.get(subagentId)) {
|
|
87
|
+
process.stdout.write("💭 Reasoning: ");
|
|
88
|
+
subagentReasoningStates.set(subagentId, true);
|
|
19
89
|
}
|
|
90
|
+
process.stdout.write(chunk);
|
|
91
|
+
},
|
|
92
|
+
onSubagentAssistantContentUpdated: (subagentId, chunk) => {
|
|
93
|
+
if (subagentReasoningStates.get(subagentId) &&
|
|
94
|
+
!subagentContentStates.get(subagentId)) {
|
|
95
|
+
process.stdout.write("\n 📝 Response: ");
|
|
96
|
+
subagentContentStates.set(subagentId, true);
|
|
97
|
+
}
|
|
98
|
+
// Stream subagent content with indentation - output only the new chunk
|
|
99
|
+
process.stdout.write(chunk);
|
|
100
|
+
},
|
|
101
|
+
onSubagentUserMessageAdded: (_subagentId, params) => {
|
|
102
|
+
// Display subagent user messages with indentation
|
|
103
|
+
process.stdout.write(`\n 👤 User: ${params.content}\n`);
|
|
104
|
+
},
|
|
105
|
+
// Error block callback
|
|
106
|
+
onErrorBlockAdded: (error) => {
|
|
107
|
+
// Display error blocks with distinct formatting
|
|
108
|
+
process.stdout.write(`\n❌ Error: ${error}\n`);
|
|
20
109
|
},
|
|
21
110
|
};
|
|
22
111
|
try {
|
|
@@ -25,38 +114,47 @@ export async function startPrintCli(options) {
|
|
|
25
114
|
callbacks,
|
|
26
115
|
restoreSessionId,
|
|
27
116
|
continueLastSession,
|
|
28
|
-
|
|
117
|
+
permissionMode: bypassPermissions ? "bypassPermissions" : undefined,
|
|
118
|
+
// 保持流式模式以获得更好的命令行用户体验
|
|
29
119
|
});
|
|
30
120
|
// Send message if provided and not empty
|
|
31
121
|
if (message && message.trim() !== "") {
|
|
32
122
|
await agent.sendMessage(message);
|
|
33
123
|
}
|
|
34
124
|
// Display usage summary before exit
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
125
|
+
if (showStats) {
|
|
126
|
+
try {
|
|
127
|
+
const usages = agent.usages;
|
|
128
|
+
const sessionFilePath = agent.sessionFilePath;
|
|
129
|
+
displayUsageSummary(usages, sessionFilePath);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// Silently ignore usage summary errors
|
|
133
|
+
}
|
|
42
134
|
}
|
|
135
|
+
// Display timing information
|
|
136
|
+
displayTimingInfo(startTime, showStats);
|
|
43
137
|
// Destroy agent and exit after sendMessage completes
|
|
44
|
-
agent.destroy();
|
|
138
|
+
await agent.destroy();
|
|
45
139
|
process.exit(0);
|
|
46
140
|
}
|
|
47
141
|
catch (error) {
|
|
48
142
|
console.error("Failed to send message:", error);
|
|
49
143
|
if (agent) {
|
|
50
144
|
// Display usage summary even on error
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
145
|
+
if (showStats) {
|
|
146
|
+
try {
|
|
147
|
+
const usages = agent.usages;
|
|
148
|
+
const sessionFilePath = agent.sessionFilePath;
|
|
149
|
+
displayUsageSummary(usages, sessionFilePath);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
// Silently ignore usage summary errors
|
|
153
|
+
}
|
|
58
154
|
}
|
|
59
|
-
|
|
155
|
+
// Display timing information even on error
|
|
156
|
+
displayTimingInfo(startTime, showStats);
|
|
157
|
+
await agent.destroy();
|
|
60
158
|
}
|
|
61
159
|
process.exit(1);
|
|
62
160
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool parameter transformation utilities for UI rendering
|
|
3
|
+
* Forces type judgment based on tool name using type assertions
|
|
4
|
+
*/
|
|
5
|
+
import { type Change, type WriteToolParameters, type EditToolParameters, type MultiEditToolParameters } from "wave-agent-sdk";
|
|
6
|
+
/**
|
|
7
|
+
* Transform Write tool parameters to changes
|
|
8
|
+
*/
|
|
9
|
+
export declare function transformWriteParameters(parameters: WriteToolParameters): Change[];
|
|
10
|
+
/**
|
|
11
|
+
* Transform Edit tool parameters to changes
|
|
12
|
+
*/
|
|
13
|
+
export declare function transformEditParameters(parameters: EditToolParameters): Change[];
|
|
14
|
+
/**
|
|
15
|
+
* Transform MultiEdit tool parameters to changes
|
|
16
|
+
*/
|
|
17
|
+
export declare function transformMultiEditParameters(parameters: MultiEditToolParameters): Change[];
|
|
18
|
+
/**
|
|
19
|
+
* Transform tool block parameters into standardized Change[] array for diff display
|
|
20
|
+
* Forces type judgment based on tool name using type assertions
|
|
21
|
+
*/
|
|
22
|
+
export declare function transformToolBlockToChanges(toolName: string, parameters: string): Change[];
|
|
23
|
+
//# sourceMappingURL=toolParameterTransforms.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolParameterTransforms.d.ts","sourceRoot":"","sources":["../../src/utils/toolParameterTransforms.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,KAAK,MAAM,EACX,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC7B,MAAM,gBAAgB,CAAC;AAmBxB;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,mBAAmB,GAC9B,MAAM,EAAE,CAOV;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,kBAAkB,GAC7B,MAAM,EAAE,CAOV;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,uBAAuB,GAClC,MAAM,EAAE,CAKV;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,MAAM,EAAE,CA2BV"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool parameter transformation utilities for UI rendering
|
|
3
|
+
* Forces type judgment based on tool name using type assertions
|
|
4
|
+
*/
|
|
5
|
+
import { logger } from "./logger.js";
|
|
6
|
+
/**
|
|
7
|
+
* Parse tool block parameters
|
|
8
|
+
*/
|
|
9
|
+
function parseToolParameters(parameters) {
|
|
10
|
+
if (!parameters) {
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(parameters);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
logger.warn("Failed to parse tool parameters:", error);
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Transform Write tool parameters to changes
|
|
23
|
+
*/
|
|
24
|
+
export function transformWriteParameters(parameters) {
|
|
25
|
+
return [
|
|
26
|
+
{
|
|
27
|
+
oldContent: "", // No previous content for write operations
|
|
28
|
+
newContent: parameters.content,
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Transform Edit tool parameters to changes
|
|
34
|
+
*/
|
|
35
|
+
export function transformEditParameters(parameters) {
|
|
36
|
+
return [
|
|
37
|
+
{
|
|
38
|
+
oldContent: parameters.old_string,
|
|
39
|
+
newContent: parameters.new_string,
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Transform MultiEdit tool parameters to changes
|
|
45
|
+
*/
|
|
46
|
+
export function transformMultiEditParameters(parameters) {
|
|
47
|
+
return parameters.edits.map((edit) => ({
|
|
48
|
+
oldContent: edit.old_string,
|
|
49
|
+
newContent: edit.new_string,
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Transform tool block parameters into standardized Change[] array for diff display
|
|
54
|
+
* Forces type judgment based on tool name using type assertions
|
|
55
|
+
*/
|
|
56
|
+
export function transformToolBlockToChanges(toolName, parameters) {
|
|
57
|
+
try {
|
|
58
|
+
if (!toolName) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
const parsedParams = parseToolParameters(parameters);
|
|
62
|
+
switch (toolName) {
|
|
63
|
+
case "Write":
|
|
64
|
+
return transformWriteParameters(parsedParams);
|
|
65
|
+
case "Edit":
|
|
66
|
+
return transformEditParameters(parsedParams);
|
|
67
|
+
case "MultiEdit":
|
|
68
|
+
return transformMultiEditParameters(parsedParams);
|
|
69
|
+
default:
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
logger.warn("Failed to transform tool block to changes:", error);
|
|
75
|
+
return [];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -11,6 +11,12 @@ export interface TokenSummary {
|
|
|
11
11
|
agent_calls: number;
|
|
12
12
|
compressions: number;
|
|
13
13
|
};
|
|
14
|
+
cache_read_input_tokens?: number;
|
|
15
|
+
cache_creation_input_tokens?: number;
|
|
16
|
+
cache_creation?: {
|
|
17
|
+
ephemeral_5m_input_tokens: number;
|
|
18
|
+
ephemeral_1h_input_tokens: number;
|
|
19
|
+
};
|
|
14
20
|
}
|
|
15
21
|
/**
|
|
16
22
|
* Calculate token usage summary by model from usage array
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usageSummary.d.ts","sourceRoot":"","sources":["../../src/utils/usageSummary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,KAAK,EAAE,GACd,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"usageSummary.d.ts","sourceRoot":"","sources":["../../src/utils/usageSummary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IAEF,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,cAAc,CAAC,EAAE;QACf,yBAAyB,EAAE,MAAM,CAAC;QAClC,yBAAyB,EAAE,MAAM,CAAC;KACnC,CAAC;CACH;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,KAAK,EAAE,GACd,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAyE9B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,KAAK,EAAE,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,IAAI,CAwHN"}
|
|
@@ -23,6 +23,31 @@ export function calculateTokenSummary(usages) {
|
|
|
23
23
|
summary.prompt_tokens += usage.prompt_tokens;
|
|
24
24
|
summary.completion_tokens += usage.completion_tokens;
|
|
25
25
|
summary.total_tokens += usage.total_tokens;
|
|
26
|
+
// Handle cache tokens if present and non-zero
|
|
27
|
+
if (usage.cache_read_input_tokens && usage.cache_read_input_tokens > 0) {
|
|
28
|
+
summary.cache_read_input_tokens =
|
|
29
|
+
(summary.cache_read_input_tokens || 0) + usage.cache_read_input_tokens;
|
|
30
|
+
}
|
|
31
|
+
if (usage.cache_creation_input_tokens &&
|
|
32
|
+
usage.cache_creation_input_tokens > 0) {
|
|
33
|
+
summary.cache_creation_input_tokens =
|
|
34
|
+
(summary.cache_creation_input_tokens || 0) +
|
|
35
|
+
usage.cache_creation_input_tokens;
|
|
36
|
+
}
|
|
37
|
+
if (usage.cache_creation &&
|
|
38
|
+
(usage.cache_creation.ephemeral_5m_input_tokens > 0 ||
|
|
39
|
+
usage.cache_creation.ephemeral_1h_input_tokens > 0)) {
|
|
40
|
+
if (!summary.cache_creation) {
|
|
41
|
+
summary.cache_creation = {
|
|
42
|
+
ephemeral_5m_input_tokens: 0,
|
|
43
|
+
ephemeral_1h_input_tokens: 0,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
summary.cache_creation.ephemeral_5m_input_tokens +=
|
|
47
|
+
usage.cache_creation.ephemeral_5m_input_tokens || 0;
|
|
48
|
+
summary.cache_creation.ephemeral_1h_input_tokens +=
|
|
49
|
+
usage.cache_creation.ephemeral_1h_input_tokens || 0;
|
|
50
|
+
}
|
|
26
51
|
// Track operation types
|
|
27
52
|
if (usage.operation_type === "agent") {
|
|
28
53
|
summary.operations.agent_calls += 1;
|
|
@@ -59,11 +84,43 @@ export function displayUsageSummary(usages, sessionFilePath) {
|
|
|
59
84
|
let totalTokens = 0;
|
|
60
85
|
let totalAgentCalls = 0;
|
|
61
86
|
let totalCompressions = 0;
|
|
87
|
+
let totalCacheRead = 0;
|
|
88
|
+
let totalCacheCreation = 0;
|
|
89
|
+
let totalCache5m = 0;
|
|
90
|
+
let totalCache1h = 0;
|
|
91
|
+
let hasCacheData = false;
|
|
62
92
|
for (const [, summary] of Object.entries(summaries)) {
|
|
63
93
|
console.log(`Model: ${summary.model}`);
|
|
64
94
|
console.log(` Prompt tokens: ${summary.prompt_tokens.toLocaleString()}`);
|
|
65
95
|
console.log(` Completion tokens: ${summary.completion_tokens.toLocaleString()}`);
|
|
66
96
|
console.log(` Total tokens: ${summary.total_tokens.toLocaleString()}`);
|
|
97
|
+
// Display cache information if available
|
|
98
|
+
if (summary.cache_read_input_tokens ||
|
|
99
|
+
summary.cache_creation_input_tokens ||
|
|
100
|
+
summary.cache_creation) {
|
|
101
|
+
hasCacheData = true;
|
|
102
|
+
console.log(" Cache Usage:");
|
|
103
|
+
if (summary.cache_read_input_tokens &&
|
|
104
|
+
summary.cache_read_input_tokens > 0) {
|
|
105
|
+
console.log(` Read from cache: ${summary.cache_read_input_tokens.toLocaleString()} tokens`);
|
|
106
|
+
totalCacheRead += summary.cache_read_input_tokens;
|
|
107
|
+
}
|
|
108
|
+
if (summary.cache_creation_input_tokens &&
|
|
109
|
+
summary.cache_creation_input_tokens > 0) {
|
|
110
|
+
console.log(` Created cache: ${summary.cache_creation_input_tokens.toLocaleString()} tokens`);
|
|
111
|
+
totalCacheCreation += summary.cache_creation_input_tokens;
|
|
112
|
+
}
|
|
113
|
+
if (summary.cache_creation) {
|
|
114
|
+
if (summary.cache_creation.ephemeral_5m_input_tokens > 0) {
|
|
115
|
+
console.log(` 5m cache: ${summary.cache_creation.ephemeral_5m_input_tokens.toLocaleString()} tokens`);
|
|
116
|
+
totalCache5m += summary.cache_creation.ephemeral_5m_input_tokens;
|
|
117
|
+
}
|
|
118
|
+
if (summary.cache_creation.ephemeral_1h_input_tokens > 0) {
|
|
119
|
+
console.log(` 1h cache: ${summary.cache_creation.ephemeral_1h_input_tokens.toLocaleString()} tokens`);
|
|
120
|
+
totalCache1h += summary.cache_creation.ephemeral_1h_input_tokens;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
67
124
|
console.log(` Operations: ${summary.operations.agent_calls} agent calls, ${summary.operations.compressions} compressions`);
|
|
68
125
|
console.log();
|
|
69
126
|
totalPrompt += summary.prompt_tokens;
|
|
@@ -77,6 +134,21 @@ export function displayUsageSummary(usages, sessionFilePath) {
|
|
|
77
134
|
console.log(` Prompt tokens: ${totalPrompt.toLocaleString()}`);
|
|
78
135
|
console.log(` Completion tokens: ${totalCompletion.toLocaleString()}`);
|
|
79
136
|
console.log(` Total tokens: ${totalTokens.toLocaleString()}`);
|
|
137
|
+
if (hasCacheData) {
|
|
138
|
+
console.log(" Cache Usage:");
|
|
139
|
+
if (totalCacheRead > 0) {
|
|
140
|
+
console.log(` Read from cache: ${totalCacheRead.toLocaleString()} tokens`);
|
|
141
|
+
}
|
|
142
|
+
if (totalCacheCreation > 0) {
|
|
143
|
+
console.log(` Created cache: ${totalCacheCreation.toLocaleString()} tokens`);
|
|
144
|
+
}
|
|
145
|
+
if (totalCache5m > 0) {
|
|
146
|
+
console.log(` 5m cache: ${totalCache5m.toLocaleString()} tokens`);
|
|
147
|
+
}
|
|
148
|
+
if (totalCache1h > 0) {
|
|
149
|
+
console.log(` 1h cache: ${totalCache1h.toLocaleString()} tokens`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
80
152
|
console.log(` Operations: ${totalAgentCalls} agent calls, ${totalCompressions} compressions`);
|
|
81
153
|
}
|
|
82
154
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wave-code",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "CLI-based code assistant powered by AI, built with React and Ink",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -24,20 +24,24 @@
|
|
|
24
24
|
"README.md"
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"
|
|
27
|
+
"chalk": "^5.6.2",
|
|
28
|
+
"diff": "^8.0.2",
|
|
29
|
+
"glob": "^13.0.0",
|
|
30
|
+
"ink": "^6.5.1",
|
|
31
|
+
"marked": "^11.2.0",
|
|
32
|
+
"marked-terminal": "^7.3.0",
|
|
28
33
|
"react": "^19.1.0",
|
|
29
34
|
"yargs": "^17.7.2",
|
|
30
|
-
"
|
|
31
|
-
"glob": "^11.0.3",
|
|
32
|
-
"wave-agent-sdk": "0.0.7"
|
|
35
|
+
"wave-agent-sdk": "0.0.10"
|
|
33
36
|
},
|
|
34
37
|
"devDependencies": {
|
|
38
|
+
"@types/marked-terminal": "^6.1.1",
|
|
35
39
|
"@types/react": "^19.1.8",
|
|
36
40
|
"@types/yargs": "^17.0.0",
|
|
37
41
|
"eslint-plugin-react": "^7.37.5",
|
|
38
42
|
"eslint-plugin-react-hooks": "^5.2.0",
|
|
39
43
|
"ink-testing-library": "^4.0.0",
|
|
40
|
-
"rimraf": "^6.
|
|
44
|
+
"rimraf": "^6.1.2",
|
|
41
45
|
"tsc-alias": "^1.8.16",
|
|
42
46
|
"tsx": "^4.20.4",
|
|
43
47
|
"vitest": "^3.2.4"
|
|
@@ -46,13 +50,14 @@
|
|
|
46
50
|
"react": ">=18.0.0"
|
|
47
51
|
},
|
|
48
52
|
"engines": {
|
|
49
|
-
"node": ">=
|
|
53
|
+
"node": ">=22.0.0"
|
|
50
54
|
},
|
|
51
55
|
"license": "MIT",
|
|
52
56
|
"scripts": {
|
|
57
|
+
"wave": "tsx src/index.ts",
|
|
53
58
|
"build": "rimraf dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
54
59
|
"type-check": "tsc --noEmit --incremental",
|
|
55
|
-
"
|
|
60
|
+
"watch": "tsc -p tsconfig.build.json --watch & tsc-alias -p tsconfig.build.json --watch",
|
|
56
61
|
"test": "vitest run",
|
|
57
62
|
"lint": "eslint --cache",
|
|
58
63
|
"format": "prettier --write ."
|