wave-agent-sdk 0.7.1 → 0.8.0

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 (168) hide show
  1. package/dist/agent.d.ts +9 -79
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +85 -302
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -1
  7. package/dist/managers/aiManager.d.ts.map +1 -1
  8. package/dist/managers/aiManager.js +20 -13
  9. package/dist/managers/backgroundTaskManager.d.ts +1 -1
  10. package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
  11. package/dist/managers/backgroundTaskManager.js +1 -1
  12. package/dist/managers/{bashManager.d.ts → bangManager.d.ts} +4 -4
  13. package/dist/managers/{bashManager.d.ts.map → bangManager.d.ts.map} +1 -1
  14. package/dist/managers/{bashManager.js → bangManager.js} +5 -6
  15. package/dist/managers/hookManager.d.ts.map +1 -1
  16. package/dist/managers/hookManager.js +12 -3
  17. package/dist/managers/messageManager.d.ts +18 -6
  18. package/dist/managers/messageManager.d.ts.map +1 -1
  19. package/dist/managers/messageManager.js +42 -20
  20. package/dist/managers/permissionManager.d.ts +22 -1
  21. package/dist/managers/permissionManager.d.ts.map +1 -1
  22. package/dist/managers/permissionManager.js +106 -85
  23. package/dist/managers/planManager.d.ts +6 -0
  24. package/dist/managers/planManager.d.ts.map +1 -1
  25. package/dist/managers/planManager.js +21 -0
  26. package/dist/managers/skillManager.d.ts +7 -2
  27. package/dist/managers/skillManager.d.ts.map +1 -1
  28. package/dist/managers/skillManager.js +30 -10
  29. package/dist/managers/slashCommandManager.d.ts +7 -0
  30. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  31. package/dist/managers/slashCommandManager.js +57 -45
  32. package/dist/managers/subagentManager.d.ts +4 -0
  33. package/dist/managers/subagentManager.d.ts.map +1 -1
  34. package/dist/managers/subagentManager.js +47 -13
  35. package/dist/managers/toolManager.d.ts +7 -1
  36. package/dist/managers/toolManager.d.ts.map +1 -1
  37. package/dist/managers/toolManager.js +15 -2
  38. package/dist/prompts/index.d.ts +0 -4
  39. package/dist/prompts/index.d.ts.map +1 -1
  40. package/dist/prompts/index.js +0 -9
  41. package/dist/services/aiService.d.ts.map +1 -1
  42. package/dist/services/aiService.js +6 -6
  43. package/dist/services/configurationService.d.ts +2 -2
  44. package/dist/services/configurationService.d.ts.map +1 -1
  45. package/dist/services/configurationService.js +4 -4
  46. package/dist/services/hook.d.ts.map +1 -1
  47. package/dist/services/hook.js +6 -0
  48. package/dist/services/initializationService.d.ts +44 -0
  49. package/dist/services/initializationService.d.ts.map +1 -0
  50. package/dist/services/initializationService.js +170 -0
  51. package/dist/services/interactionService.d.ts +29 -0
  52. package/dist/services/interactionService.d.ts.map +1 -0
  53. package/dist/services/interactionService.js +97 -0
  54. package/dist/services/session.js +1 -1
  55. package/dist/services/taskManager.d.ts +5 -0
  56. package/dist/services/taskManager.d.ts.map +1 -1
  57. package/dist/services/taskManager.js +16 -2
  58. package/dist/tools/bashTool.d.ts.map +1 -1
  59. package/dist/tools/bashTool.js +7 -18
  60. package/dist/tools/editTool.js +1 -1
  61. package/dist/tools/exitPlanMode.js +1 -1
  62. package/dist/tools/lspTool.d.ts +2 -0
  63. package/dist/tools/lspTool.d.ts.map +1 -1
  64. package/dist/tools/lspTool.js +144 -52
  65. package/dist/tools/skillTool.d.ts.map +1 -1
  66. package/dist/tools/skillTool.js +97 -2
  67. package/dist/tools/taskManagementTools.d.ts.map +1 -1
  68. package/dist/tools/taskManagementTools.js +23 -2
  69. package/dist/tools/taskTool.d.ts.map +1 -1
  70. package/dist/tools/taskTool.js +9 -15
  71. package/dist/tools/types.d.ts +1 -2
  72. package/dist/tools/types.d.ts.map +1 -1
  73. package/dist/tools/writeTool.js +1 -1
  74. package/dist/types/agent.d.ts +64 -0
  75. package/dist/types/agent.d.ts.map +1 -0
  76. package/dist/types/agent.js +1 -0
  77. package/dist/types/commands.d.ts +0 -4
  78. package/dist/types/commands.d.ts.map +1 -1
  79. package/dist/types/config.d.ts +1 -1
  80. package/dist/types/config.d.ts.map +1 -1
  81. package/dist/types/hooks.d.ts +3 -1
  82. package/dist/types/hooks.d.ts.map +1 -1
  83. package/dist/types/hooks.js +1 -0
  84. package/dist/types/index.d.ts +1 -0
  85. package/dist/types/index.d.ts.map +1 -1
  86. package/dist/types/index.js +1 -0
  87. package/dist/types/messaging.d.ts +3 -3
  88. package/dist/types/messaging.d.ts.map +1 -1
  89. package/dist/types/skills.d.ts +13 -0
  90. package/dist/types/skills.d.ts.map +1 -1
  91. package/dist/utils/commandPathResolver.d.ts +3 -36
  92. package/dist/utils/commandPathResolver.d.ts.map +1 -1
  93. package/dist/utils/commandPathResolver.js +16 -93
  94. package/dist/utils/configValidator.d.ts +2 -2
  95. package/dist/utils/configValidator.d.ts.map +1 -1
  96. package/dist/utils/configValidator.js +4 -6
  97. package/dist/utils/containerSetup.d.ts +3 -4
  98. package/dist/utils/containerSetup.d.ts.map +1 -1
  99. package/dist/utils/containerSetup.js +14 -9
  100. package/dist/utils/customCommands.d.ts +2 -3
  101. package/dist/utils/customCommands.d.ts.map +1 -1
  102. package/dist/utils/customCommands.js +20 -60
  103. package/dist/utils/gitUtils.d.ts +25 -0
  104. package/dist/utils/gitUtils.d.ts.map +1 -1
  105. package/dist/utils/gitUtils.js +75 -0
  106. package/dist/utils/markdownParser.d.ts +4 -0
  107. package/dist/utils/markdownParser.d.ts.map +1 -1
  108. package/dist/utils/markdownParser.js +33 -0
  109. package/dist/utils/messageOperations.d.ts +16 -7
  110. package/dist/utils/messageOperations.d.ts.map +1 -1
  111. package/dist/utils/messageOperations.js +45 -20
  112. package/dist/utils/nameGenerator.d.ts +1 -1
  113. package/dist/utils/nameGenerator.d.ts.map +1 -1
  114. package/dist/utils/nameGenerator.js +10 -6
  115. package/dist/utils/skillParser.d.ts.map +1 -1
  116. package/dist/utils/skillParser.js +48 -0
  117. package/package.json +1 -1
  118. package/src/agent.ts +103 -458
  119. package/src/index.ts +2 -2
  120. package/src/managers/aiManager.ts +23 -17
  121. package/src/managers/backgroundTaskManager.ts +2 -2
  122. package/src/managers/{bashManager.ts → bangManager.ts} +11 -8
  123. package/src/managers/hookManager.ts +13 -3
  124. package/src/managers/messageManager.ts +55 -26
  125. package/src/managers/permissionManager.ts +121 -98
  126. package/src/managers/planManager.ts +26 -0
  127. package/src/managers/skillManager.ts +51 -14
  128. package/src/managers/slashCommandManager.ts +75 -55
  129. package/src/managers/subagentManager.ts +57 -13
  130. package/src/managers/toolManager.ts +22 -2
  131. package/src/prompts/index.ts +0 -15
  132. package/src/services/aiService.ts +9 -12
  133. package/src/services/configurationService.ts +4 -4
  134. package/src/services/hook.ts +7 -0
  135. package/src/services/initializationService.ts +291 -0
  136. package/src/services/interactionService.ts +171 -0
  137. package/src/services/session.ts +1 -1
  138. package/src/services/taskManager.ts +18 -2
  139. package/src/tools/bashTool.ts +8 -18
  140. package/src/tools/editTool.ts +1 -1
  141. package/src/tools/exitPlanMode.ts +1 -1
  142. package/src/tools/lsTool.ts +1 -1
  143. package/src/tools/lspTool.ts +184 -52
  144. package/src/tools/skillTool.ts +127 -2
  145. package/src/tools/taskManagementTools.ts +32 -2
  146. package/src/tools/taskTool.ts +13 -15
  147. package/src/tools/types.ts +1 -2
  148. package/src/tools/writeTool.ts +1 -1
  149. package/src/types/agent.ts +83 -0
  150. package/src/types/commands.ts +0 -6
  151. package/src/types/config.ts +1 -1
  152. package/src/types/hooks.ts +5 -1
  153. package/src/types/index.ts +1 -0
  154. package/src/types/messaging.ts +3 -3
  155. package/src/types/skills.ts +13 -0
  156. package/src/utils/commandPathResolver.ts +14 -117
  157. package/src/utils/configValidator.ts +5 -9
  158. package/src/utils/containerSetup.ts +17 -14
  159. package/src/utils/customCommands.ts +20 -83
  160. package/src/utils/gitUtils.ts +75 -0
  161. package/src/utils/markdownParser.ts +47 -0
  162. package/src/utils/messageOperations.ts +58 -28
  163. package/src/utils/nameGenerator.ts +10 -6
  164. package/src/utils/skillParser.ts +52 -0
  165. package/dist/managers/backgroundBashManager.d.ts +0 -27
  166. package/dist/managers/backgroundBashManager.d.ts.map +0 -1
  167. package/dist/managers/backgroundBashManager.js +0 -169
  168. package/src/managers/backgroundBashManager.ts +0 -206
package/src/index.ts CHANGED
@@ -22,6 +22,6 @@ export * from "./utils/stringUtils.js";
22
22
  export * from "./utils/customCommands.js";
23
23
  export * from "./utils/hookMatcher.js";
24
24
  export * from "./utils/tokenCalculation.js";
25
-
26
- // Export types
25
+ export * from "./utils/gitUtils.js";
26
+ export * from "./utils/nameGenerator.js";
27
27
  export * from "./types/index.js";
@@ -132,7 +132,17 @@ export class AIManager {
132
132
  * Get filtered tool configuration based on tools list
133
133
  */
134
134
  private getFilteredToolsConfig(tools?: string[]) {
135
- const allTools = this.toolManager.getToolsConfig();
135
+ // Get available subagents and skills for dynamic prompts
136
+ const availableSubagents = this.subagentManager?.getConfigurations();
137
+ const availableSkills = this.skillManager
138
+ ?.getAvailableSkills()
139
+ .filter((skill) => !skill.disableModelInvocation);
140
+
141
+ const allTools = this.toolManager.getToolsConfig({
142
+ availableSubagents,
143
+ availableSkills,
144
+ workdir: this.workdir,
145
+ });
136
146
 
137
147
  // If no tools specified, return all tools
138
148
  if (!tools || tools.length === 0) {
@@ -241,7 +251,7 @@ export class AIManager {
241
251
  prompt_tokens: compressionResult.usage.prompt_tokens,
242
252
  completion_tokens: compressionResult.usage.completion_tokens,
243
253
  total_tokens: compressionResult.usage.total_tokens,
244
- model: model || this.getModelConfig().agentModel,
254
+ model: model || this.getModelConfig().model,
245
255
  operation_type: "compress",
246
256
  };
247
257
  }
@@ -383,10 +393,6 @@ export class AIManager {
383
393
  }
384
394
  }
385
395
 
386
- // Get available subagents and skills for dynamic prompts
387
- const availableSubagents = this.subagentManager?.getConfigurations();
388
- const availableSkills = this.skillManager?.getAvailableSkills();
389
-
390
396
  // Call AI service with streaming callbacks if enabled
391
397
  const callAgentOptions: CallAgentOptions = {
392
398
  gatewayConfig: this.getGatewayConfig(),
@@ -406,8 +412,6 @@ export class AIManager {
406
412
  language: this.getLanguage(),
407
413
  isSubagent: !!this.subagentType,
408
414
  planMode: planModeOptions,
409
- availableSubagents,
410
- availableSkills,
411
415
  },
412
416
  ), // Pass custom system prompt
413
417
  maxTokens: maxTokens, // Pass max tokens override
@@ -512,7 +516,7 @@ export class AIManager {
512
516
  prompt_tokens: result.usage.prompt_tokens,
513
517
  completion_tokens: result.usage.completion_tokens,
514
518
  total_tokens: result.usage.total_tokens,
515
- model: model || this.getModelConfig().agentModel,
519
+ model: model || this.getModelConfig().model,
516
520
  operation_type: "agent",
517
521
  // Preserve cache fields if present
518
522
  ...(result.usage.cache_read_input_tokens !== undefined && {
@@ -553,12 +557,6 @@ export class AIManager {
553
557
  }
554
558
  }
555
559
 
556
- if (result.finish_reason === "length" && toolCalls.length === 0) {
557
- this.messageManager.addErrorBlock(
558
- "AI response was truncated due to length limit. Please try to reduce the complexity of your request or split it into smaller parts.",
559
- );
560
- }
561
-
562
560
  if (toolCalls.length > 0) {
563
561
  // Execute all tools in parallel using Promise.all
564
562
  const toolExecutionPromises = toolCalls.map(
@@ -716,8 +714,8 @@ export class AIManager {
716
714
  model,
717
715
  );
718
716
 
719
- // Check if there are tool operations, if so automatically initiate next AI service call
720
- if (toolCalls.length > 0) {
717
+ // Check if there are tool operations or response was truncated, if so automatically initiate next AI service call
718
+ if (toolCalls.length > 0 || result.finish_reason === "length") {
721
719
  // Record committed snapshots to message history
722
720
  if (this.reversionManager) {
723
721
  const snapshots =
@@ -750,6 +748,14 @@ export class AIManager {
750
748
  "Some tools were manually backgrounded, stopping recursion.",
751
749
  );
752
750
  } else if (!isCurrentlyAborted) {
751
+ // If response was truncated and no tools were called, add a continuation message
752
+ if (result.finish_reason === "length" && toolCalls.length === 0) {
753
+ this.messageManager.addUserMessage({
754
+ content:
755
+ "Your response was cut off because it exceeded the output token limit. Please break your work into smaller pieces. Continue from where you left off.",
756
+ });
757
+ }
758
+
753
759
  // Recursively call AI service, increment recursion depth, and pass same configuration
754
760
  await this.sendAIMessage({
755
761
  recursionDepth: recursionDepth + 1,
@@ -5,7 +5,7 @@ import { logger } from "../utils/globalLogger.js";
5
5
  import { Container } from "../utils/container.js";
6
6
 
7
7
  export interface BackgroundTaskManagerCallbacks {
8
- onTasksChange?: (tasks: BackgroundTask[]) => void;
8
+ onBackgroundTasksChange?: (tasks: BackgroundTask[]) => void;
9
9
  }
10
10
 
11
11
  export interface BackgroundTaskManagerOptions {
@@ -28,7 +28,7 @@ export class BackgroundTaskManager {
28
28
  }
29
29
 
30
30
  private notifyTasksChange(): void {
31
- this.callbacks.onTasksChange?.(Array.from(this.tasks.values()));
31
+ this.callbacks.onBackgroundTasksChange?.(Array.from(this.tasks.values()));
32
32
  }
33
33
 
34
34
  public generateId(): string {
@@ -2,7 +2,7 @@ import { spawn, type ChildProcess } from "child_process";
2
2
  import type { MessageManager } from "./messageManager.js";
3
3
  import { Container } from "../utils/container.js";
4
4
 
5
- export interface BashManagerOptions {
5
+ export interface BangManagerOptions {
6
6
  workdir: string;
7
7
  }
8
8
 
@@ -11,14 +11,14 @@ export interface CommandExecutionResult {
11
11
  output: string;
12
12
  }
13
13
 
14
- export class BashManager {
14
+ export class BangManager {
15
15
  private workdir: string;
16
16
  public isCommandRunning = false;
17
17
  private currentProcess: ChildProcess | null = null;
18
18
 
19
19
  constructor(
20
20
  private container: Container,
21
- options: BashManagerOptions,
21
+ options: BangManagerOptions,
22
22
  ) {
23
23
  this.workdir = options.workdir;
24
24
  }
@@ -38,8 +38,8 @@ export class BashManager {
38
38
 
39
39
  this.setCommandRunning(true);
40
40
 
41
- // Add command output placeholder
42
- this.messageManager.addCommandOutputMessage(command);
41
+ // Add bang placeholder
42
+ this.messageManager.addBangMessage(command);
43
43
 
44
44
  return new Promise<number>((resolve) => {
45
45
  const child = spawn(command, {
@@ -56,7 +56,6 @@ export class BashManager {
56
56
 
57
57
  const updateOutput = (newData: string) => {
58
58
  outputBuffer += newData;
59
- this.messageManager.updateCommandOutputMessage(command, outputBuffer);
60
59
  };
61
60
 
62
61
  child.stdout?.on("data", (data) => {
@@ -70,7 +69,11 @@ export class BashManager {
70
69
  child.on("exit", (code, signal) => {
71
70
  const exitCode = code === null && signal ? 130 : (code ?? 0);
72
71
 
73
- this.messageManager.completeCommandMessage(command, exitCode);
72
+ this.messageManager.completeBangMessage(
73
+ command,
74
+ exitCode,
75
+ outputBuffer,
76
+ );
74
77
 
75
78
  this.setCommandRunning(false);
76
79
  this.currentProcess = null;
@@ -79,7 +82,7 @@ export class BashManager {
79
82
 
80
83
  child.on("error", (error) => {
81
84
  updateOutput(`\nError: ${error.message}\n`);
82
- this.messageManager.completeCommandMessage(command, 1);
85
+ this.messageManager.completeBangMessage(command, 1, outputBuffer);
83
86
 
84
87
  this.setCommandRunning(false);
85
88
  this.currentProcess = null;
@@ -378,6 +378,11 @@ export class HookManager {
378
378
  });
379
379
  return { shouldBlock: true, errorMessage };
380
380
 
381
+ case "WorktreeCreate":
382
+ // Non-blocking for now, just show error in error block
383
+ messageManager.addErrorBlock(errorMessage);
384
+ return { shouldBlock: false };
385
+
381
386
  default:
382
387
  return { shouldBlock: false };
383
388
  }
@@ -577,7 +582,8 @@ export class HookManager {
577
582
  (event === "UserPromptSubmit" ||
578
583
  event === "Stop" ||
579
584
  event === "Notification" ||
580
- event === "SubagentStop") &&
585
+ event === "SubagentStop" ||
586
+ event === "WorktreeCreate") &&
581
587
  context.toolName !== undefined
582
588
  ) {
583
589
  logger?.warn(
@@ -653,7 +659,8 @@ export class HookManager {
653
659
  event === "UserPromptSubmit" ||
654
660
  event === "Stop" ||
655
661
  event === "Notification" ||
656
- event === "SubagentStop"
662
+ event === "SubagentStop" ||
663
+ event === "WorktreeCreate"
657
664
  ) {
658
665
  return true;
659
666
  }
@@ -704,7 +711,8 @@ export class HookManager {
704
711
  (event === "UserPromptSubmit" ||
705
712
  event === "Stop" ||
706
713
  event === "Notification" ||
707
- event === "SubagentStop") &&
714
+ event === "SubagentStop" ||
715
+ event === "WorktreeCreate") &&
708
716
  config.matcher
709
717
  ) {
710
718
  errors.push(`${prefix}: Event ${event} should not have a matcher`);
@@ -743,6 +751,7 @@ export class HookManager {
743
751
  Stop: 0,
744
752
  SubagentStop: 0,
745
753
  Notification: 0,
754
+ WorktreeCreate: 0,
746
755
  },
747
756
  };
748
757
  }
@@ -754,6 +763,7 @@ export class HookManager {
754
763
  Stop: 0,
755
764
  SubagentStop: 0,
756
765
  Notification: 0,
766
+ WorktreeCreate: 0,
757
767
  };
758
768
 
759
769
  let totalConfigs = 0;
@@ -3,9 +3,9 @@ import {
3
3
  updateToolBlockInMessage,
4
4
  addErrorBlockToMessage,
5
5
  addUserMessageToMessages,
6
- addCommandOutputMessage,
7
- updateCommandOutputInMessage,
8
- completeCommandInMessage,
6
+ addBangMessage,
7
+ updateBangInMessage,
8
+ completeBangInMessage,
9
9
  removeLastUserMessage,
10
10
  UserMessageParams,
11
11
  type AgentToolBlockUpdateParams,
@@ -48,10 +48,10 @@ export interface MessageManagerCallbacks {
48
48
  type: "project" | "user",
49
49
  storagePath: string,
50
50
  ) => void;
51
- // Bash command callback
52
- onAddCommandOutputMessage?: (command: string) => void;
53
- onUpdateCommandOutputMessage?: (command: string, output: string) => void;
54
- onCompleteCommandMessage?: (command: string, exitCode: number) => void;
51
+ // Bang callback
52
+ onAddBangMessage?: (command: string) => void;
53
+ onUpdateBangMessage?: (command: string, output: string) => void;
54
+ onCompleteBangMessage?: (command: string, exitCode: number) => void;
55
55
  onSlashCommandsChange?: (commands: SlashCommand[]) => void;
56
56
  onInfoBlockAdded?: (content: string) => void;
57
57
  // Rewind callbacks
@@ -85,6 +85,7 @@ export class MessageManager {
85
85
  private filesInContext: Set<string> = new Set(); // Track files mentioned in the conversation
86
86
  private sessionType: "main" | "subagent";
87
87
  private subagentType?: string;
88
+ private _usages: Usage[] = [];
88
89
 
89
90
  constructor(
90
91
  private container: Container,
@@ -128,6 +129,10 @@ export class MessageManager {
128
129
  return [...this.messages];
129
130
  }
130
131
 
132
+ public getUsages(): Usage[] {
133
+ return [...this._usages];
134
+ }
135
+
131
136
  public getlatestTotalTokens(): number {
132
137
  return this.latestTotalTokens;
133
138
  }
@@ -266,8 +271,9 @@ export class MessageManager {
266
271
  */
267
272
  public clearMessages(): void {
268
273
  this.setMessages([]);
269
- this.setSessionId(generateSessionId());
270
- this.rootSessionId = this.sessionId;
274
+ const newSessionId = generateSessionId();
275
+ this.rootSessionId = newSessionId;
276
+ this.setSessionId(newSessionId);
271
277
  this.setlatestTotalTokens(0);
272
278
  this.savedMessageCount = 0; // Reset saved message count
273
279
  }
@@ -463,47 +469,70 @@ export class MessageManager {
463
469
  }
464
470
  }
465
471
 
466
- // Bash command related message operations
467
- public addCommandOutputMessage(command: string): void {
468
- const updatedMessages = addCommandOutputMessage({
472
+ // Bang related message operations
473
+ public addBangMessage(command: string): void {
474
+ const updatedMessages = addBangMessage({
469
475
  messages: this.messages,
470
476
  command,
471
477
  });
472
478
  this.setMessages(updatedMessages);
473
- this.callbacks.onAddCommandOutputMessage?.(command);
479
+ this.callbacks.onAddBangMessage?.(command);
474
480
  }
475
481
 
476
- public updateCommandOutputMessage(command: string, output: string): void {
477
- const updatedMessages = updateCommandOutputInMessage({
482
+ public updateBangMessage(command: string, output: string): void {
483
+ const updatedMessages = updateBangInMessage({
478
484
  messages: this.messages,
479
485
  command,
480
486
  output,
481
487
  });
482
488
  this.setMessages(updatedMessages);
483
- this.callbacks.onUpdateCommandOutputMessage?.(command, output);
489
+ this.callbacks.onUpdateBangMessage?.(command, output);
484
490
  }
485
491
 
486
- public completeCommandMessage(command: string, exitCode: number): void {
487
- const updatedMessages = completeCommandInMessage({
492
+ public completeBangMessage(
493
+ command: string,
494
+ exitCode: number,
495
+ output?: string,
496
+ ): void {
497
+ const updatedMessages = completeBangInMessage({
488
498
  messages: this.messages,
489
499
  command,
490
500
  exitCode,
501
+ output,
491
502
  });
492
503
  this.setMessages(updatedMessages);
493
- this.callbacks.onCompleteCommandMessage?.(command, exitCode);
504
+ this.callbacks.onCompleteBangMessage?.(command, exitCode);
494
505
  }
495
506
 
496
507
  /**
497
- * Trigger usage change callback with all usage data from assistant messages
508
+ * Rebuild usage array from messages containing usage metadata
509
+ * Called during session restoration to reconstruct usage tracking
498
510
  */
499
- public triggerUsageChange(): void {
500
- const usages: Usage[] = [];
501
- for (const message of this.messages) {
511
+ public rebuildUsageFromMessages(messages: Message[]): void {
512
+ this._usages = [];
513
+ messages.forEach((message) => {
502
514
  if (message.role === "assistant" && message.usage) {
503
- usages.push(message.usage);
515
+ this._usages.push(message.usage);
504
516
  }
505
- }
506
- this.callbacks.onUsagesChange?.(usages);
517
+ });
518
+ // Trigger callback after rebuilding usage array
519
+ this.triggerUsageChange();
520
+ }
521
+
522
+ /**
523
+ * Add usage data to the tracking array and trigger callbacks
524
+ * @param usage Usage data from AI operations
525
+ */
526
+ public addUsage(usage: Usage): void {
527
+ this._usages.push(usage);
528
+ this.triggerUsageChange();
529
+ }
530
+
531
+ /**
532
+ * Trigger usage change callback with all usage data from assistant messages
533
+ */
534
+ public triggerUsageChange(): void {
535
+ this.callbacks.onUsagesChange?.([...this._usages]);
507
536
  }
508
537
 
509
538
  /**