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.
Files changed (93) hide show
  1. package/README.md +3 -3
  2. package/dist/cli.d.ts +1 -0
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +2 -2
  5. package/dist/components/App.d.ts +1 -0
  6. package/dist/components/App.d.ts.map +1 -1
  7. package/dist/components/App.js +4 -4
  8. package/dist/components/BashHistorySelector.d.ts.map +1 -1
  9. package/dist/components/BashHistorySelector.js +17 -3
  10. package/dist/components/ChatInterface.d.ts.map +1 -1
  11. package/dist/components/ChatInterface.js +6 -24
  12. package/dist/components/CommandSelector.js +4 -4
  13. package/dist/components/Confirmation.d.ts +11 -0
  14. package/dist/components/Confirmation.d.ts.map +1 -0
  15. package/dist/components/Confirmation.js +148 -0
  16. package/dist/components/DiffDisplay.d.ts +8 -0
  17. package/dist/components/DiffDisplay.d.ts.map +1 -0
  18. package/dist/components/DiffDisplay.js +168 -0
  19. package/dist/components/FileSelector.d.ts +2 -4
  20. package/dist/components/FileSelector.d.ts.map +1 -1
  21. package/dist/components/FileSelector.js +2 -2
  22. package/dist/components/InputBox.d.ts.map +1 -1
  23. package/dist/components/InputBox.js +30 -50
  24. package/dist/components/Markdown.d.ts +6 -0
  25. package/dist/components/Markdown.d.ts.map +1 -0
  26. package/dist/components/Markdown.js +22 -0
  27. package/dist/components/MemoryDisplay.js +1 -1
  28. package/dist/components/MessageItem.d.ts +8 -0
  29. package/dist/components/MessageItem.d.ts.map +1 -0
  30. package/dist/components/MessageItem.js +15 -0
  31. package/dist/components/MessageList.d.ts +1 -1
  32. package/dist/components/MessageList.d.ts.map +1 -1
  33. package/dist/components/MessageList.js +33 -33
  34. package/dist/components/ReasoningDisplay.d.ts +8 -0
  35. package/dist/components/ReasoningDisplay.d.ts.map +1 -0
  36. package/dist/components/ReasoningDisplay.js +10 -0
  37. package/dist/components/SubagentBlock.d.ts +0 -1
  38. package/dist/components/SubagentBlock.d.ts.map +1 -1
  39. package/dist/components/SubagentBlock.js +29 -30
  40. package/dist/components/ToolResultDisplay.d.ts.map +1 -1
  41. package/dist/components/ToolResultDisplay.js +6 -5
  42. package/dist/contexts/useChat.d.ts +14 -2
  43. package/dist/contexts/useChat.d.ts.map +1 -1
  44. package/dist/contexts/useChat.js +128 -17
  45. package/dist/hooks/useInputManager.d.ts +6 -1
  46. package/dist/hooks/useInputManager.d.ts.map +1 -1
  47. package/dist/hooks/useInputManager.js +32 -2
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +30 -5
  50. package/dist/managers/InputManager.d.ts +11 -1
  51. package/dist/managers/InputManager.d.ts.map +1 -1
  52. package/dist/managers/InputManager.js +77 -26
  53. package/dist/print-cli.d.ts +2 -0
  54. package/dist/print-cli.d.ts.map +1 -1
  55. package/dist/print-cli.js +121 -23
  56. package/dist/utils/toolParameterTransforms.d.ts +23 -0
  57. package/dist/utils/toolParameterTransforms.d.ts.map +1 -0
  58. package/dist/utils/toolParameterTransforms.js +77 -0
  59. package/dist/utils/usageSummary.d.ts +6 -0
  60. package/dist/utils/usageSummary.d.ts.map +1 -1
  61. package/dist/utils/usageSummary.js +72 -0
  62. package/package.json +13 -8
  63. package/src/cli.tsx +3 -1
  64. package/src/components/App.tsx +7 -3
  65. package/src/components/BashHistorySelector.tsx +26 -3
  66. package/src/components/ChatInterface.tsx +38 -54
  67. package/src/components/CommandSelector.tsx +5 -5
  68. package/src/components/Confirmation.tsx +253 -0
  69. package/src/components/DiffDisplay.tsx +300 -0
  70. package/src/components/FileSelector.tsx +4 -6
  71. package/src/components/InputBox.tsx +58 -87
  72. package/src/components/Markdown.tsx +29 -0
  73. package/src/components/MemoryDisplay.tsx +1 -1
  74. package/src/components/MessageItem.tsx +96 -0
  75. package/src/components/MessageList.tsx +140 -202
  76. package/src/components/ReasoningDisplay.tsx +33 -0
  77. package/src/components/SubagentBlock.tsx +56 -84
  78. package/src/components/ToolResultDisplay.tsx +9 -5
  79. package/src/contexts/useChat.tsx +194 -21
  80. package/src/hooks/useInputManager.ts +40 -3
  81. package/src/index.ts +45 -5
  82. package/src/managers/InputManager.ts +101 -27
  83. package/src/print-cli.ts +143 -21
  84. package/src/utils/toolParameterTransforms.ts +104 -0
  85. package/src/utils/usageSummary.ts +109 -0
  86. package/dist/components/DiffViewer.d.ts +0 -9
  87. package/dist/components/DiffViewer.d.ts.map +0 -1
  88. package/dist/components/DiffViewer.js +0 -221
  89. package/dist/utils/fileSearch.d.ts +0 -20
  90. package/dist/utils/fileSearch.d.ts.map +0 -1
  91. package/dist/utils/fileSearch.js +0 -102
  92. package/src/components/DiffViewer.tsx +0 -321
  93. package/src/utils/fileSearch.ts +0 -133
@@ -1,4 +1,4 @@
1
- import { searchFiles as searchFilesUtil } from "../utils/fileSearch.js";
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
- // Note: type parameter will be used in future for different handling logic
332
- console.debug(`Memory type selected: ${type}`);
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
- if (this.showFileSelector && this.atPosition >= 0) {
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 Enter should be handled by selector components
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 ||
@@ -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
@@ -1 +1 @@
1
- {"version":3,"file":"print-cli.d.ts","sourceRoot":"","sources":["../src/print-cli.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,eAAe;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAmE3E"}
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 { restoreSessionId, continueLastSession, message } = options;
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: (content) => {
16
- // Only output the content field, not tool calls
17
- if (content) {
18
- console.log(content);
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
- logger,
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
- try {
36
- const usages = agent.usages;
37
- const sessionFilePath = agent.sessionFilePath;
38
- displayUsageSummary(usages, sessionFilePath);
39
- }
40
- catch {
41
- // Silently ignore usage summary errors
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
- try {
52
- const usages = agent.usages;
53
- const sessionFilePath = agent.sessionFilePath;
54
- displayUsageSummary(usages, sessionFilePath);
55
- }
56
- catch {
57
- // Silently ignore usage summary errors
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
- agent.destroy();
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,CA2C9B;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,KAAK,EAAE,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,IAAI,CAgDN"}
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.5",
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
- "ink": "^6.0.1",
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
- "diff": "^8.0.2",
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.0.1",
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": ">=16.0.0"
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
- "dev": "tsc -p tsconfig.build.json --watch & tsc-alias -p tsconfig.build.json --watch",
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 ."