@xagent-ai/cli 1.3.0 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/.github/release.yml +76 -0
  2. package/.github/workflows/ci.yml +3 -0
  3. package/.github/workflows/release.yml +11 -17
  4. package/README.md +2 -2
  5. package/README_CN.md +2 -2
  6. package/dist/agents.d.ts.map +1 -1
  7. package/dist/agents.js +7 -3
  8. package/dist/agents.js.map +1 -1
  9. package/dist/ai-client/factory.d.ts +0 -12
  10. package/dist/ai-client/factory.d.ts.map +1 -1
  11. package/dist/ai-client/factory.js +0 -32
  12. package/dist/ai-client/factory.js.map +1 -1
  13. package/dist/ai-client/index.js +1 -1
  14. package/dist/ai-client/index.js.map +1 -1
  15. package/dist/ai-client/providers/anthropic.d.ts.map +1 -1
  16. package/dist/ai-client/providers/anthropic.js +10 -4
  17. package/dist/ai-client/providers/anthropic.js.map +1 -1
  18. package/dist/ai-client/providers/openai.d.ts.map +1 -1
  19. package/dist/ai-client/providers/openai.js +8 -4
  20. package/dist/ai-client/providers/openai.js.map +1 -1
  21. package/dist/ai-client/providers/remote.d.ts +0 -1
  22. package/dist/ai-client/providers/remote.d.ts.map +1 -1
  23. package/dist/ai-client/providers/remote.js +11 -10
  24. package/dist/ai-client/providers/remote.js.map +1 -1
  25. package/dist/ai-client/types.d.ts +14 -0
  26. package/dist/ai-client/types.d.ts.map +1 -1
  27. package/dist/ai-client/types.js +17 -0
  28. package/dist/ai-client/types.js.map +1 -1
  29. package/dist/ai-client-factory.d.ts.map +1 -1
  30. package/dist/ai-client-factory.js +4 -4
  31. package/dist/ai-client-factory.js.map +1 -1
  32. package/dist/auth.d.ts.map +1 -1
  33. package/dist/auth.js +10 -12
  34. package/dist/auth.js.map +1 -1
  35. package/dist/cancellation.d.ts.map +1 -1
  36. package/dist/cancellation.js +3 -5
  37. package/dist/cancellation.js.map +1 -1
  38. package/dist/checkpoint.d.ts +1 -0
  39. package/dist/checkpoint.d.ts.map +1 -1
  40. package/dist/checkpoint.js +38 -4
  41. package/dist/checkpoint.js.map +1 -1
  42. package/dist/cli.js +132 -32
  43. package/dist/cli.js.map +1 -1
  44. package/dist/config.js +1 -1
  45. package/dist/config.js.map +1 -1
  46. package/dist/context-compressor.d.ts +1 -2
  47. package/dist/context-compressor.d.ts.map +1 -1
  48. package/dist/context-compressor.js +22 -17
  49. package/dist/context-compressor.js.map +1 -1
  50. package/dist/conversation.d.ts +1 -1
  51. package/dist/conversation.d.ts.map +1 -1
  52. package/dist/conversation.js +8 -7
  53. package/dist/conversation.js.map +1 -1
  54. package/dist/gui-subagent/action-parser/actionParser.js +2 -2
  55. package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
  56. package/dist/gui-subagent/agent/gui-agent.d.ts +10 -0
  57. package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
  58. package/dist/gui-subagent/agent/gui-agent.js +105 -32
  59. package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
  60. package/dist/gui-subagent/index.d.ts +7 -0
  61. package/dist/gui-subagent/index.d.ts.map +1 -1
  62. package/dist/gui-subagent/index.js +2 -0
  63. package/dist/gui-subagent/index.js.map +1 -1
  64. package/dist/gui-subagent/operator/computer-operator.d.ts.map +1 -1
  65. package/dist/gui-subagent/operator/computer-operator.js +2 -0
  66. package/dist/gui-subagent/operator/computer-operator.js.map +1 -1
  67. package/dist/input-processor.js +2 -2
  68. package/dist/input-processor.js.map +1 -1
  69. package/dist/logger.d.ts.map +1 -1
  70. package/dist/logger.js +1 -1
  71. package/dist/logger.js.map +1 -1
  72. package/dist/mcp.d.ts +2 -1
  73. package/dist/mcp.d.ts.map +1 -1
  74. package/dist/mcp.js +84 -21
  75. package/dist/mcp.js.map +1 -1
  76. package/dist/memory.d.ts.map +1 -1
  77. package/dist/memory.js +3 -3
  78. package/dist/memory.js.map +1 -1
  79. package/dist/output-util.d.ts +27 -0
  80. package/dist/output-util.d.ts.map +1 -0
  81. package/dist/output-util.js +74 -0
  82. package/dist/output-util.js.map +1 -0
  83. package/dist/retry.js +1 -1
  84. package/dist/retry.js.map +1 -1
  85. package/dist/ripgrep.d.ts.map +1 -1
  86. package/dist/ripgrep.js +5 -3
  87. package/dist/ripgrep.js.map +1 -1
  88. package/dist/sdk-output-adapter.d.ts +265 -0
  89. package/dist/sdk-output-adapter.d.ts.map +1 -0
  90. package/dist/sdk-output-adapter.js +701 -0
  91. package/dist/sdk-output-adapter.js.map +1 -0
  92. package/dist/sdk-session.d.ts +13 -0
  93. package/dist/sdk-session.d.ts.map +1 -0
  94. package/dist/sdk-session.js +50 -0
  95. package/dist/sdk-session.js.map +1 -0
  96. package/dist/session-manager.js +3 -3
  97. package/dist/session-manager.js.map +1 -1
  98. package/dist/session.d.ts +96 -2
  99. package/dist/session.d.ts.map +1 -1
  100. package/dist/session.js +849 -262
  101. package/dist/session.js.map +1 -1
  102. package/dist/shell.d.ts.map +1 -1
  103. package/dist/shell.js +5 -4
  104. package/dist/shell.js.map +1 -1
  105. package/dist/skill-installer.js +3 -3
  106. package/dist/skill-installer.js.map +1 -1
  107. package/dist/skill-invoker.d.ts +1 -1
  108. package/dist/skill-invoker.d.ts.map +1 -1
  109. package/dist/skill-invoker.js +2 -2
  110. package/dist/skill-invoker.js.map +1 -1
  111. package/dist/skill-loader.js +6 -5
  112. package/dist/skill-loader.js.map +1 -1
  113. package/dist/skill-manager.d.ts.map +1 -1
  114. package/dist/skill-manager.js +3 -2
  115. package/dist/skill-manager.js.map +1 -1
  116. package/dist/slash-commands.d.ts +1 -1
  117. package/dist/slash-commands.d.ts.map +1 -1
  118. package/dist/slash-commands.js +24 -11
  119. package/dist/slash-commands.js.map +1 -1
  120. package/dist/smart-approval.d.ts +20 -1
  121. package/dist/smart-approval.d.ts.map +1 -1
  122. package/dist/smart-approval.js +58 -1
  123. package/dist/smart-approval.js.map +1 -1
  124. package/dist/system-prompt-generator.js +3 -3
  125. package/dist/system-prompt-generator.js.map +1 -1
  126. package/dist/theme.d.ts.map +1 -1
  127. package/dist/theme.js +9 -8
  128. package/dist/theme.js.map +1 -1
  129. package/dist/tools.d.ts +15 -0
  130. package/dist/tools.d.ts.map +1 -1
  131. package/dist/tools.js +487 -215
  132. package/dist/tools.js.map +1 -1
  133. package/dist/types.d.ts +57 -0
  134. package/dist/types.d.ts.map +1 -1
  135. package/dist/types.js +49 -0
  136. package/dist/types.js.map +1 -1
  137. package/dist/update.d.ts.map +1 -1
  138. package/dist/update.js +12 -9
  139. package/dist/update.js.map +1 -1
  140. package/dist/workflow.d.ts.map +1 -1
  141. package/dist/workflow.js +1 -2
  142. package/dist/workflow.js.map +1 -1
  143. package/docs/third-party-models.md +16 -15
  144. package/package.json +3 -1
  145. package/src/agents.ts +7 -3
  146. package/src/ai-client/factory.ts +1 -36
  147. package/src/ai-client/index.ts +1 -1
  148. package/src/ai-client/providers/anthropic.ts +12 -3
  149. package/src/ai-client/providers/openai.ts +10 -4
  150. package/src/ai-client/providers/remote.ts +13 -10
  151. package/src/ai-client/types.ts +19 -0
  152. package/src/ai-client-factory.ts +5 -5
  153. package/src/auth.ts +11 -13
  154. package/src/cancellation.ts +3 -6
  155. package/src/checkpoint.ts +41 -4
  156. package/src/cli.ts +154 -37
  157. package/src/config.ts +1 -1
  158. package/src/context-compressor.ts +27 -22
  159. package/src/conversation.ts +9 -7
  160. package/src/gui-subagent/action-parser/actionParser.ts +2 -2
  161. package/src/gui-subagent/agent/gui-agent.ts +117 -34
  162. package/src/gui-subagent/index.ts +8 -0
  163. package/src/gui-subagent/operator/computer-operator.ts +2 -1
  164. package/src/input-processor.ts +2 -2
  165. package/src/logger.ts +2 -4
  166. package/src/mcp.ts +87 -23
  167. package/src/memory.ts +3 -4
  168. package/src/output-util.ts +80 -0
  169. package/src/retry.ts +1 -1
  170. package/src/ripgrep.ts +5 -3
  171. package/src/sdk-output-adapter.ts +842 -0
  172. package/src/sdk-session.ts +62 -0
  173. package/src/session-manager.ts +3 -3
  174. package/src/session.ts +942 -302
  175. package/src/shell.ts +6 -5
  176. package/src/skill-installer.ts +3 -3
  177. package/src/skill-invoker.ts +3 -4
  178. package/src/skill-loader.ts +7 -7
  179. package/src/skill-manager.ts +4 -3
  180. package/src/slash-commands.ts +24 -16
  181. package/src/smart-approval.ts +76 -1
  182. package/src/system-prompt-generator.ts +3 -3
  183. package/src/theme.ts +10 -9
  184. package/src/tools.ts +563 -267
  185. package/src/types.ts +118 -0
  186. package/src/update.ts +12 -9
  187. package/src/workflow.ts +2 -4
  188. package/test/cli-launch.test.ts +279 -0
  189. package/vitest.config.ts +2 -0
  190. /package/{.eslintrc.js → .eslintrc.cjs} +0 -0
@@ -0,0 +1,842 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SDK Output Adapter
5
+ *
6
+ * This module provides output formatting for SDK mode.
7
+ * It converts CLI-style output into JSON format for programmatic consumption.
8
+ */
9
+
10
+ import { SessionInput, SessionOutput } from './types.js';
11
+
12
+ // GUI Agent types (re-exported for SDK usage)
13
+ export type GUIAgentStatus = 'init' | 'running' | 'paused' | 'end' | 'error' | 'user_stopped' | 'call_llm';
14
+
15
+ export interface GUIAgentOutput {
16
+ type: 'status' | 'conversation' | 'action' | 'screenshot' | 'error' | 'complete';
17
+ timestamp: number;
18
+ data: Record<string, unknown>;
19
+ }
20
+
21
+ export interface GUIAgentConversation {
22
+ from: 'human' | 'assistant';
23
+ value: string;
24
+ screenshotBase64?: string;
25
+ screenshotContext?: {
26
+ size: { width: number; height: number };
27
+ mime?: string;
28
+ scaleFactor: number;
29
+ };
30
+ actionType?: string;
31
+ actionInputs?: Record<string, unknown>;
32
+ timing?: {
33
+ start: number;
34
+ end: number;
35
+ cost: number;
36
+ };
37
+ predictionParsed?: Array<{
38
+ action_type: string;
39
+ [key: string]: unknown;
40
+ }>;
41
+ }
42
+
43
+ export interface GUIAgentHandler {
44
+ (output: GUIAgentOutput): void;
45
+ }
46
+
47
+ export interface SdkOutputMessage {
48
+ type: 'output' | 'input' | 'system' | 'tool' | 'error' | 'thinking' | 'result';
49
+ subtype?: string;
50
+ timestamp: number;
51
+ data: Record<string, unknown>;
52
+ }
53
+
54
+ export interface SdkStreamEvent {
55
+ event_type: string;
56
+ timestamp: number;
57
+ data: Record<string, unknown>;
58
+ }
59
+
60
+ export type OutputHandler = (message: SdkOutputMessage) => void;
61
+
62
+ export class SdkOutputAdapter {
63
+ private outputHandler: OutputHandler;
64
+ private indentLevel: number;
65
+
66
+ constructor(outputHandler?: OutputHandler) {
67
+ this.outputHandler = outputHandler || ((msg) => {
68
+ process.stdout.write(JSON.stringify(msg) + '\n');
69
+ });
70
+ this.indentLevel = 0;
71
+ }
72
+
73
+ /**
74
+ * Set indent level for output formatting.
75
+ */
76
+ setIndentLevel(level: number): void {
77
+ this.indentLevel = level;
78
+ }
79
+
80
+ /**
81
+ * Get current indent string.
82
+ */
83
+ getIndent(): string {
84
+ return ' '.repeat(this.indentLevel);
85
+ }
86
+
87
+ /**
88
+ * Format and output a welcome message.
89
+ */
90
+ outputWelcome(language: 'zh' | 'en', executionMode: string): void {
91
+ const messages = {
92
+ zh: {
93
+ title: '🤖 XAGENT CLI',
94
+ version: 'v1.0.0',
95
+ subtitle: 'AI-powered command-line assistant',
96
+ modeLabel: '当前模式',
97
+ modeDescription: '智能审批与安全检查',
98
+ help: '输入 /help 查看可用命令'
99
+ },
100
+ en: {
101
+ title: '🤖 XAGENT CLI',
102
+ version: 'v1.0.0',
103
+ subtitle: 'AI-powered command-line assistant',
104
+ modeLabel: 'Current Mode',
105
+ modeDescription: 'Smart approval with intelligent security checks',
106
+ help: 'Type /help to see available commands'
107
+ }
108
+ };
109
+
110
+ const msg = messages[language];
111
+ const config = this.getModeConfig(executionMode);
112
+
113
+ this.output({
114
+ type: 'system',
115
+ subtype: 'welcome',
116
+ timestamp: Date.now(),
117
+ data: {
118
+ title: msg.title,
119
+ version: msg.version,
120
+ subtitle: msg.subtitle,
121
+ mode: {
122
+ name: executionMode,
123
+ icon: config.icon,
124
+ description: msg.modeDescription
125
+ },
126
+ help: msg.help
127
+ }
128
+ });
129
+ }
130
+
131
+ /**
132
+ * Format and output ready signal.
133
+ * This is sent when the CLI is fully initialized and ready to accept requests.
134
+ */
135
+ outputReady(): void {
136
+ this.output({
137
+ type: 'system',
138
+ subtype: 'ready',
139
+ timestamp: Date.now(),
140
+ data: {
141
+ status: 'initialized',
142
+ message: 'CLI is ready to accept requests'
143
+ }
144
+ });
145
+ }
146
+
147
+ /**
148
+ * Format and output request done signal.
149
+ * This is sent when a user request has been fully processed.
150
+ */
151
+ outputRequestDone(requestId: string, status: 'success' | 'cancelled' | 'error' = 'success'): void {
152
+ this.output({
153
+ type: 'result',
154
+ subtype: 'request_done',
155
+ timestamp: Date.now(),
156
+ data: {
157
+ requestId,
158
+ status,
159
+ message: status === 'success' ? 'Request completed successfully' : `Request ${status}`
160
+ }
161
+ });
162
+ }
163
+
164
+ /**
165
+ * Format and output AI response.
166
+ */
167
+ outputAssistant(content: string, reasoningContent?: string): void {
168
+ this.output({
169
+ type: 'output',
170
+ subtype: 'assistant',
171
+ timestamp: Date.now(),
172
+ data: {
173
+ content,
174
+ reasoningContent
175
+ }
176
+ });
177
+ }
178
+
179
+ /**
180
+ * Format and output tool execution.
181
+ */
182
+ outputToolStart(toolName: string, params: Record<string, unknown>): void {
183
+ this.output({
184
+ type: 'tool',
185
+ subtype: 'start',
186
+ timestamp: Date.now(),
187
+ data: {
188
+ tool: toolName,
189
+ params,
190
+ status: 'running'
191
+ }
192
+ });
193
+ }
194
+
195
+ /**
196
+ * Format and output tool result.
197
+ */
198
+ outputToolResult(toolName: string, result: unknown, duration?: number): void {
199
+ this.output({
200
+ type: 'tool',
201
+ subtype: 'result',
202
+ timestamp: Date.now(),
203
+ data: {
204
+ tool: toolName,
205
+ result,
206
+ duration,
207
+ status: 'completed'
208
+ }
209
+ });
210
+ }
211
+
212
+ /**
213
+ * Format and output tool error.
214
+ */
215
+ outputToolError(toolName: string, error: string): void {
216
+ this.output({
217
+ type: 'tool',
218
+ subtype: 'error',
219
+ timestamp: Date.now(),
220
+ data: {
221
+ tool: toolName,
222
+ error,
223
+ status: 'error'
224
+ }
225
+ });
226
+ }
227
+
228
+ /**
229
+ * Format and output thinking content.
230
+ */
231
+ outputThinking(reasoningContent: string, displayMode: string = 'compact'): void {
232
+ const maxLength = displayMode === 'full' ? undefined : 500;
233
+ const truncated = maxLength && reasoningContent.length > maxLength;
234
+ const displayContent = truncated ? reasoningContent.substring(0, maxLength) + '... (truncated)' : reasoningContent;
235
+
236
+ this.output({
237
+ type: 'thinking',
238
+ subtype: displayMode,
239
+ timestamp: Date.now(),
240
+ data: {
241
+ content: displayContent,
242
+ originalLength: reasoningContent.length,
243
+ truncated,
244
+ displayMode
245
+ }
246
+ });
247
+ }
248
+
249
+ /**
250
+ * Format and output system message.
251
+ */
252
+ outputSystem(subtype: string, data: Record<string, unknown>): void {
253
+ this.output({
254
+ type: 'system',
255
+ subtype,
256
+ timestamp: Date.now(),
257
+ data
258
+ });
259
+ }
260
+
261
+ /**
262
+ * Format and output MCP loading status.
263
+ */
264
+ outputMCPLoading(count: number): void {
265
+ this.output({
266
+ type: 'system',
267
+ subtype: 'mcp_loading',
268
+ timestamp: Date.now(),
269
+ data: { count }
270
+ });
271
+ }
272
+
273
+ /**
274
+ * Format and output MCP server registering status.
275
+ */
276
+ outputMCPRegistering(name: string, transport: string): void {
277
+ this.output({
278
+ type: 'system',
279
+ subtype: 'mcp_registering',
280
+ timestamp: Date.now(),
281
+ data: { name, transport }
282
+ });
283
+ }
284
+
285
+ /**
286
+ * Format and output MCP connecting status.
287
+ */
288
+ outputMCPConnecting(count: number): void {
289
+ this.output({
290
+ type: 'system',
291
+ subtype: 'mcp_connecting',
292
+ timestamp: Date.now(),
293
+ data: { count }
294
+ });
295
+ }
296
+
297
+ /**
298
+ * Format and output MCP connected result.
299
+ */
300
+ outputMCPConnected(total: number, connected: number, toolsAvailable: number): void {
301
+ this.output({
302
+ type: 'system',
303
+ subtype: 'mcp_connected',
304
+ timestamp: Date.now(),
305
+ data: { total, connected, toolsAvailable }
306
+ });
307
+ }
308
+
309
+ /**
310
+ * Format and output MCP connection failed warning.
311
+ */
312
+ outputMCPConnectionFailed(message: string): void {
313
+ this.output({
314
+ type: 'system',
315
+ subtype: 'mcp_connection_failed',
316
+ timestamp: Date.now(),
317
+ data: { message }
318
+ });
319
+ }
320
+
321
+ /**
322
+ * Format and output error message.
323
+ */
324
+ outputError(message: string, context?: Record<string, unknown>): void {
325
+ this.output({
326
+ type: 'error',
327
+ subtype: 'general',
328
+ timestamp: Date.now(),
329
+ data: {
330
+ message,
331
+ ...context
332
+ }
333
+ });
334
+ }
335
+
336
+ /**
337
+ * Format and output warning message.
338
+ */
339
+ outputWarning(message: string): void {
340
+ this.output({
341
+ type: 'system',
342
+ subtype: 'warning',
343
+ timestamp: Date.now(),
344
+ data: { message }
345
+ });
346
+ }
347
+
348
+ /**
349
+ * Format and output success message.
350
+ */
351
+ outputSuccess(message: string): void {
352
+ this.output({
353
+ type: 'system',
354
+ subtype: 'success',
355
+ timestamp: Date.now(),
356
+ data: { message }
357
+ });
358
+ }
359
+
360
+ /**
361
+ * Format and output info message.
362
+ */
363
+ outputInfo(message: string): void {
364
+ this.output({
365
+ type: 'system',
366
+ subtype: 'info',
367
+ timestamp: Date.now(),
368
+ data: { message }
369
+ });
370
+ }
371
+
372
+ /**
373
+ * Format and output context compression notification.
374
+ */
375
+ outputContextCompression(reason: string, originalSize: number, compressedSize: number, reductionPercent: number): void {
376
+ this.output({
377
+ type: 'system',
378
+ subtype: 'context_compression',
379
+ timestamp: Date.now(),
380
+ data: {
381
+ reason,
382
+ originalSize,
383
+ compressedSize,
384
+ reductionPercent
385
+ }
386
+ });
387
+ }
388
+
389
+ /**
390
+ * Format and output context compression triggered.
391
+ */
392
+ outputContextCompressionTriggered(reason: string): void {
393
+ this.output({
394
+ type: 'system',
395
+ subtype: 'context_compression_triggered',
396
+ timestamp: Date.now(),
397
+ data: { reason }
398
+ });
399
+ }
400
+
401
+ /**
402
+ * Format and output context compression result.
403
+ */
404
+ outputContextCompressionResult(
405
+ originalSize: number,
406
+ compressedSize: number,
407
+ reductionPercent: number,
408
+ originalMessageCount: number,
409
+ compressedMessageCount: number
410
+ ): void {
411
+ this.output({
412
+ type: 'system',
413
+ subtype: 'context_compression_result',
414
+ timestamp: Date.now(),
415
+ data: {
416
+ originalSize,
417
+ compressedSize,
418
+ reductionPercent,
419
+ originalMessageCount,
420
+ compressedMessageCount
421
+ }
422
+ });
423
+ }
424
+
425
+ /**
426
+ * Format and output context compression summary.
427
+ */
428
+ outputContextCompressionSummary(
429
+ summary: string,
430
+ preview: string,
431
+ isTruncated: boolean,
432
+ totalLength: number
433
+ ): void {
434
+ this.output({
435
+ type: 'system',
436
+ subtype: 'context_compression_summary',
437
+ timestamp: Date.now(),
438
+ data: {
439
+ summary,
440
+ preview,
441
+ isTruncated,
442
+ totalLength
443
+ }
444
+ });
445
+ }
446
+
447
+ /**
448
+ * Format and output session result.
449
+ */
450
+ outputResult(duration: number, numTurns: number, status: 'completed' | 'cancelled' | 'error'): void {
451
+ this.output({
452
+ type: 'result',
453
+ timestamp: Date.now(),
454
+ data: {
455
+ duration_ms: duration,
456
+ num_turns: numTurns,
457
+ status
458
+ }
459
+ });
460
+ }
461
+
462
+ /**
463
+ * Format and output progress/spinner.
464
+ */
465
+ outputProgress(text: string, status: 'start' | 'succeed' | 'fail' | 'update'): void {
466
+ this.output({
467
+ type: 'system',
468
+ subtype: 'progress',
469
+ timestamp: Date.now(),
470
+ data: {
471
+ text,
472
+ status
473
+ }
474
+ });
475
+ }
476
+
477
+ /**
478
+ * Format and output agent switch.
479
+ */
480
+ outputAgentSwitch(agentName: string, agentDescription?: string): void {
481
+ this.output({
482
+ type: 'system',
483
+ subtype: 'agent_switch',
484
+ timestamp: Date.now(),
485
+ data: {
486
+ agent: agentName,
487
+ description: agentDescription
488
+ }
489
+ });
490
+ }
491
+
492
+ /**
493
+ * Format and output command execution.
494
+ */
495
+ outputCommand(command: string, status: 'running' | 'completed' | 'error'): void {
496
+ this.output({
497
+ type: 'tool',
498
+ subtype: 'command',
499
+ timestamp: Date.now(),
500
+ data: {
501
+ command,
502
+ status
503
+ }
504
+ });
505
+ }
506
+
507
+ // ==================== SDK Approval Request ====================
508
+
509
+ /**
510
+ * Format and output approval request (for SDK mode).
511
+ * This is sent when a potentially risky operation needs user confirmation.
512
+ */
513
+ outputApprovalRequest(params: {
514
+ requestId: string;
515
+ toolName: string;
516
+ params: Record<string, unknown>;
517
+ riskLevel: string;
518
+ description: string;
519
+ aiAnalysis?: string;
520
+ }): void {
521
+ this.output({
522
+ type: 'system',
523
+ subtype: 'approval_request',
524
+ timestamp: Date.now(),
525
+ data: {
526
+ requestId: params.requestId,
527
+ toolName: params.toolName,
528
+ params: params.params,
529
+ riskLevel: params.riskLevel,
530
+ description: params.description,
531
+ aiAnalysis: params.aiAnalysis,
532
+ approved: false // Default to not approved, client must respond
533
+ }
534
+ });
535
+ }
536
+
537
+ /**
538
+ * Format and output approval response received (for SDK mode logging).
539
+ */
540
+ outputApprovalResponse(requestId: string, approved: boolean): void {
541
+ this.output({
542
+ type: 'system',
543
+ subtype: 'approval_response',
544
+ timestamp: Date.now(),
545
+ data: {
546
+ requestId,
547
+ approved
548
+ }
549
+ });
550
+ }
551
+
552
+ // ==================== SDK Question Request ====================
553
+
554
+ /**
555
+ * Format and output question request (for SDK mode).
556
+ * This is sent when the agent needs to ask the user questions.
557
+ */
558
+ outputQuestionRequest(params: {
559
+ requestId: string;
560
+ questions: Array<{
561
+ question: string;
562
+ header?: string;
563
+ options?: string[];
564
+ multiSelect?: boolean;
565
+ }>;
566
+ }): void {
567
+ this.output({
568
+ type: 'system',
569
+ subtype: 'question_request',
570
+ timestamp: Date.now(),
571
+ data: {
572
+ requestId: params.requestId,
573
+ questions: params.questions
574
+ }
575
+ });
576
+ }
577
+
578
+ /**
579
+ * Format and output question response received (for SDK mode logging).
580
+ */
581
+ outputQuestionResponse(requestId: string, answers: string[]): void {
582
+ this.output({
583
+ type: 'system',
584
+ subtype: 'question_response',
585
+ timestamp: Date.now(),
586
+ data: {
587
+ requestId,
588
+ answers
589
+ }
590
+ });
591
+ }
592
+
593
+ // ==================== GUI Agent Output Methods ====================
594
+
595
+ /**
596
+ * Format and output GUI agent start.
597
+ */
598
+ outputGUIAgentStart(description: string, mode: 'local' | 'remote'): void {
599
+ this.output({
600
+ type: 'system',
601
+ subtype: 'gui_agent_start',
602
+ timestamp: Date.now(),
603
+ data: {
604
+ description,
605
+ mode
606
+ }
607
+ });
608
+ }
609
+
610
+ /**
611
+ * Format and output GUI agent status update.
612
+ */
613
+ outputGUIAgentStatus(status: GUIAgentStatus, iteration?: number, error?: string): void {
614
+ this.output({
615
+ type: 'system',
616
+ subtype: `gui_status_${status}`,
617
+ timestamp: Date.now(),
618
+ data: {
619
+ status,
620
+ iteration,
621
+ error
622
+ }
623
+ });
624
+ }
625
+
626
+ /**
627
+ * Format and output GUI agent action/step.
628
+ */
629
+ outputGUIAgentAction(iteration: number, actionType: string, cost?: number): void {
630
+ this.output({
631
+ type: 'output',
632
+ subtype: 'gui_action',
633
+ timestamp: Date.now(),
634
+ data: {
635
+ iteration,
636
+ actionType,
637
+ cost
638
+ }
639
+ });
640
+ }
641
+
642
+ /**
643
+ * Format and output GUI agent conversation (screenshot).
644
+ */
645
+ outputGUIConversation(data: {
646
+ iteration: number;
647
+ from: 'human' | 'assistant';
648
+ actionType?: string;
649
+ indentLevel?: number;
650
+ timing?: { start: number; end: number; cost: number };
651
+ }): void {
652
+ this.output({
653
+ type: 'output',
654
+ subtype: 'gui_conversation',
655
+ timestamp: Date.now(),
656
+ data
657
+ });
658
+ }
659
+
660
+ /**
661
+ * Format and output GUI agent completion.
662
+ */
663
+ outputGUIAgentComplete(description: string, iterations: number): void {
664
+ this.output({
665
+ type: 'system',
666
+ subtype: 'gui_complete',
667
+ timestamp: Date.now(),
668
+ data: {
669
+ description,
670
+ iterations,
671
+ message: `GUI task completed in ${iterations} iterations`
672
+ }
673
+ });
674
+ }
675
+
676
+ /**
677
+ * Format and output GUI agent cancellation.
678
+ */
679
+ outputGUIAgentCancelled(description: string): void {
680
+ this.output({
681
+ type: 'system',
682
+ subtype: 'gui_cancelled',
683
+ timestamp: Date.now(),
684
+ data: {
685
+ description,
686
+ message: 'GUI task cancelled by user'
687
+ }
688
+ });
689
+ }
690
+
691
+ /**
692
+ * Format and output GUI agent error.
693
+ */
694
+ outputGUIAgentError(description: string, error: string): void {
695
+ this.output({
696
+ type: 'error',
697
+ subtype: 'gui_error',
698
+ timestamp: Date.now(),
699
+ data: {
700
+ description,
701
+ error
702
+ }
703
+ });
704
+ }
705
+
706
+ /**
707
+ * Create a GUI Agent output handler that maps GUIAgentOutput to SDK format.
708
+ * This handler can be passed directly to GUIAgent.
709
+ */
710
+ createGUIAgentHandler(): GUIAgentHandler {
711
+ return (output: GUIAgentOutput) => {
712
+ switch (output.type) {
713
+ case 'action':
714
+ this.output({
715
+ type: 'system',
716
+ subtype: 'gui_action',
717
+ timestamp: output.timestamp,
718
+ data: output.data
719
+ });
720
+ break;
721
+ case 'status':
722
+ this.outputGUIAgentStatus(
723
+ output.data.status as GUIAgentStatus,
724
+ output.data.iteration as number | undefined,
725
+ output.data.error as string | undefined
726
+ );
727
+ break;
728
+ case 'conversation':
729
+ this.outputGUIConversation({
730
+ iteration: output.data.iteration as number,
731
+ from: output.data.from as 'human' | 'assistant',
732
+ actionType: output.data.actionType as string | undefined,
733
+ indentLevel: output.data.indentLevel as number | undefined,
734
+ timing: output.data.timing as { start: number; end: number; cost: number } | undefined
735
+ });
736
+ break;
737
+ case 'complete':
738
+ this.output({
739
+ type: 'system',
740
+ subtype: 'gui_complete',
741
+ timestamp: output.timestamp,
742
+ data: output.data
743
+ });
744
+ break;
745
+ case 'error':
746
+ this.output({
747
+ type: 'error',
748
+ subtype: 'gui_error',
749
+ timestamp: output.timestamp,
750
+ data: output.data
751
+ });
752
+ break;
753
+ case 'screenshot':
754
+ this.output({
755
+ type: 'output',
756
+ subtype: 'gui_screenshot',
757
+ timestamp: output.timestamp,
758
+ data: output.data
759
+ });
760
+ break;
761
+ }
762
+ };
763
+ }
764
+
765
+ /**
766
+ * Output a raw message.
767
+ */
768
+ output(message: SdkOutputMessage): void {
769
+ this.outputHandler(message);
770
+ }
771
+
772
+ /**
773
+ * Get mode configuration.
774
+ */
775
+ private getModeConfig(mode: string): { color: string; icon: string; description: string } {
776
+ const modeConfigs: Record<string, { color: string; icon: string; description: string }> = {
777
+ yolo: {
778
+ color: 'red',
779
+ icon: '🔥',
780
+ description: 'Execute commands without confirmation'
781
+ },
782
+ accept_edits: {
783
+ color: 'yellow',
784
+ icon: '✅',
785
+ description: 'Accept all edits automatically'
786
+ },
787
+ plan: {
788
+ color: 'blue',
789
+ icon: '🧠',
790
+ description: 'Plan before executing'
791
+ },
792
+ default: {
793
+ color: 'green',
794
+ icon: '⚡',
795
+ description: 'Safe execution with confirmations'
796
+ },
797
+ smart: {
798
+ color: 'cyan',
799
+ icon: '✨',
800
+ description: 'Smart approval with intelligent security checks'
801
+ }
802
+ };
803
+
804
+ return modeConfigs[mode.toLowerCase()] || modeConfigs.default;
805
+ }
806
+
807
+ /**
808
+ * Convert a SessionInput to SDK format.
809
+ */
810
+ static formatSessionInput(input: SessionInput): SdkOutputMessage {
811
+ return {
812
+ type: 'input',
813
+ timestamp: input.timestamp,
814
+ data: {
815
+ inputType: input.type,
816
+ content: input.content,
817
+ rawInput: input.rawInput,
818
+ filePath: input.filePath
819
+ }
820
+ };
821
+ }
822
+
823
+ /**
824
+ * Convert a SessionOutput to SDK format.
825
+ */
826
+ static formatSessionOutput(output: SessionOutput): SdkOutputMessage {
827
+ return {
828
+ type: 'output',
829
+ timestamp: output.timestamp,
830
+ data: {
831
+ role: output.role,
832
+ content: output.content,
833
+ toolName: output.toolName,
834
+ toolParams: output.toolParams,
835
+ toolResult: output.toolResult,
836
+ duration: output.duration,
837
+ reasoning_content: output.reasoning_content,
838
+ tool_calls: output.tool_calls
839
+ }
840
+ };
841
+ }
842
+ }