-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathIOpenCodeClient.cs
More file actions
767 lines (677 loc) · 36.4 KB
/
Copy pathIOpenCodeClient.cs
File metadata and controls
767 lines (677 loc) · 36.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
using LionFire.OpenCode.Serve.Models;
using LionFire.OpenCode.Serve.Models.Events;
namespace LionFire.OpenCode.Serve;
/// <summary>
/// Interface for the OpenCode client, providing access to all OpenCode serve API operations.
/// </summary>
/// <remarks>
/// <para>
/// This interface defines the contract for communicating with an OpenCode serve API
/// instance. It provides comprehensive access to all 67+ endpoints including:
/// sessions, messages, files, PTYs, MCP servers, permissions, events, and more.
/// </para>
/// <para>
/// Implementations should be thread-safe and support concurrent operations.
/// Most operations support an optional directory parameter that scopes the operation
/// to a specific instance/directory context.
/// </para>
/// <para>
/// Based on OpenCode serve API specification version 0.0.3.
/// </para>
/// </remarks>
/// <example>
/// Basic usage:
/// <code>
/// await using var client = new OpenCodeClient();
///
/// // Create and interact with a session
/// var session = await client.CreateSessionAsync(directory: "/my/project");
/// var message = await client.PromptAsync(session.Id, new SendMessageRequest
/// {
/// Parts = new List<PartInput> { new TextPartInput { Type = "text", Text = "Hello!" } }
/// });
///
/// // Stream events
/// await foreach (var ev in client.SubscribeToEventsAsync(directory: "/my/project"))
/// {
/// Console.WriteLine($"Event: {ev.Type}");
/// }
/// </code>
/// </example>
public interface IOpenCodeClient : IAsyncDisposable
{
#region Global Events
/// <summary>
/// Subscribes to global events from the OpenCode system using server-sent events.
/// </summary>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>An async enumerable of <see cref="GlobalEvent"/> instances.</returns>
IAsyncEnumerable<GlobalEvent> SubscribeToGlobalEventsAsync(CancellationToken cancellationToken = default);
#endregion
#region Projects
/// <summary>
/// Lists all projects that have been opened with OpenCode.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="Project"/> instances.</returns>
Task<List<Project>> ListProjectsAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets the current project for the specified directory.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The current <see cref="Project"/>.</returns>
Task<Project> GetCurrentProjectAsync(string? directory = null, CancellationToken cancellationToken = default);
#endregion
#region Sessions
/// <summary>
/// Lists all sessions.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="Session"/> instances.</returns>
Task<List<Session>> ListSessionsAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Lists sessions with filtering and pagination options.
/// </summary>
/// <param name="options">Filtering and pagination options.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="Session"/> instances matching the filter criteria.</returns>
/// <remarks>
/// <para>
/// This overload provides advanced filtering capabilities including:
/// </para>
/// <list type="bullet">
/// <item><description>Date range filtering (created/updated before/after)</description></item>
/// <item><description>Title search (case-insensitive substring match)</description></item>
/// <item><description>Status filtering (idle, busy, retry)</description></item>
/// <item><description>Shared session filtering</description></item>
/// <item><description>Parent/child relationship filtering</description></item>
/// <item><description>Pagination with skip/limit</description></item>
/// <item><description>Configurable sort order</description></item>
/// </list>
/// </remarks>
/// <example>
/// <code>
/// // Get the 10 most recently updated sessions from the last week
/// var sessions = await client.ListSessionsAsync(new SessionListOptions
/// {
/// Limit = 10,
/// CreatedAfter = DateTimeOffset.UtcNow.AddDays(-7),
/// SortOrder = SessionSortOrder.UpdatedDescending
/// });
/// </code>
/// </example>
Task<List<Session>> ListSessionsAsync(SessionListOptions options, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new session.
/// </summary>
/// <param name="request">Optional request with parentID and title.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The created <see cref="Session"/>.</returns>
Task<Session> CreateSessionAsync(CreateSessionRequest? request = null, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets the session status for the specified directory.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The <see cref="SessionStatus"/>.</returns>
Task<SessionStatus> GetSessionStatusAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets a session by ID.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The <see cref="Session"/>.</returns>
Task<Session> GetSessionAsync(string sessionId, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Deletes a session.
/// </summary>
/// <param name="sessionId">The session ID to delete.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task DeleteSessionAsync(string sessionId, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Updates a session (e.g., changes title).
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="request">The update request.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The updated <see cref="Session"/>.</returns>
Task<Session> UpdateSessionAsync(string sessionId, UpdateSessionRequest request, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Aborts a running session.
/// </summary>
/// <param name="sessionId">The session ID to abort.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task AbortSessionAsync(string sessionId, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets child sessions of a session.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of child <see cref="Session"/> instances.</returns>
Task<List<Session>> GetSessionChildrenAsync(string sessionId, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Executes a command in a session.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="request">The command execution request.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task ExecuteSessionCommandAsync(string sessionId, ExecuteCommandRequest request, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets the diff for a session (or up to a specific message).
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="messageId">Optional message ID to diff up to.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="FileDiff"/> instances.</returns>
Task<List<FileDiff>> GetSessionDiffAsync(string sessionId, string? messageId = null, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Forks a session, creating a new session from an existing one.
/// </summary>
/// <param name="sessionId">The session ID to fork.</param>
/// <param name="request">Optional fork request with messageID.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The forked <see cref="Session"/>.</returns>
Task<Session> ForkSessionAsync(string sessionId, ForkSessionRequest? request = null, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Initializes a session with agent and model settings.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="request">The initialization request.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task InitializeSessionAsync(string sessionId, InitSessionRequest request, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Reverts a session to a previous message state.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="request">The revert request specifying which message to revert to.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task RevertSessionAsync(string sessionId, RevertSessionRequest request, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Unrests a previously reverted session.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task UnrevertSessionAsync(string sessionId, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Shares a session, generating a shareable URL.
/// </summary>
/// <param name="sessionId">The session ID to share.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The <see cref="Session"/> with share information.</returns>
Task<Session> ShareSessionAsync(string sessionId, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Unshares a session, removing the shareable URL.
/// </summary>
/// <param name="sessionId">The session ID to unshare.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task UnshareSessionAsync(string sessionId, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Executes a shell command in a session.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="request">The shell command execution request.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task ExecuteSessionShellAsync(string sessionId, ExecuteShellRequest request, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Summarizes a session (creates a compact summary).
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="request">Optional summarize request with messageID.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task SummarizeSessionAsync(string sessionId, SummarizeSessionRequest? request = null, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets the todo list for a session.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="Todo"/> items.</returns>
Task<List<Todo>> GetSessionTodosAsync(string sessionId, string? directory = null, CancellationToken cancellationToken = default);
#endregion
#region Messages
/// <summary>
/// Lists messages in a session.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="limit">Optional limit on number of messages to return.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="MessageWithParts"/> instances.</returns>
Task<List<MessageWithParts>> ListMessagesAsync(string sessionId, int? limit = null, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Lists messages in a session with pagination and filtering options.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="options">Pagination and filtering options.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="MessageWithParts"/> instances.</returns>
/// <remarks>
/// <para>
/// This overload supports two pagination strategies:
/// </para>
/// <list type="bullet">
/// <item>
/// <description>
/// <strong>Offset-based</strong>: Use Skip and Limit for traditional page navigation.
/// </description>
/// </item>
/// <item>
/// <description>
/// <strong>Cursor-based</strong>: Use Before or After message IDs for stable pagination.
/// Recommended for real-time scenarios or large message histories.
/// </description>
/// </item>
/// </list>
/// </remarks>
/// <example>
/// <code>
/// // Offset-based: Get page 2 with 20 messages per page
/// var page2 = await client.ListMessagesAsync(sessionId, new MessageListOptions
/// {
/// Skip = 20,
/// Limit = 20
/// });
///
/// // Cursor-based: Get 20 messages before a specific message
/// var olderMessages = await client.ListMessagesAsync(sessionId, new MessageListOptions
/// {
/// Before = "msg_abc123",
/// Limit = 20
/// });
/// </code>
/// </example>
Task<List<MessageWithParts>> ListMessagesAsync(string sessionId, MessageListOptions options, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Sends a prompt to a session and waits for the complete response.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="request">The message request.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The <see cref="MessageWithParts"/> response.</returns>
Task<MessageWithParts> PromptAsync(string sessionId, SendMessageRequest request, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Sends a prompt to a session with a custom timeout.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="request">The message request.</param>
/// <param name="timeout">The timeout for this specific operation, overriding the default.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The <see cref="MessageWithParts"/> response.</returns>
/// <exception cref="TimeoutException">Thrown when the operation exceeds the specified timeout.</exception>
/// <remarks>
/// <para>
/// Use this overload when you need to set a custom timeout for a specific operation,
/// such as when sending a complex prompt that may require more time to process.
/// </para>
/// <para>
/// The timeout parameter overrides both the client's default timeout and the
/// MessageTimeout configuration.
/// </para>
/// </remarks>
/// <example>
/// <code>
/// // Send a complex prompt with a 10-minute timeout
/// var response = await client.PromptAsync(
/// sessionId,
/// new SendMessageRequest { Parts = { PartInput.TextInput("Complex task...") } },
/// timeout: TimeSpan.FromMinutes(10)
/// );
/// </code>
/// </example>
Task<MessageWithParts> PromptAsync(string sessionId, SendMessageRequest request, TimeSpan timeout, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Sends a prompt to a session asynchronously (non-blocking).
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="request">The message request.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task PromptAsyncNonBlocking(string sessionId, SendMessageRequest request, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets a specific message from a session.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="messageId">The message ID.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The <see cref="MessageWithParts"/>.</returns>
Task<MessageWithParts> GetMessageAsync(string sessionId, string messageId, string? directory = null, CancellationToken cancellationToken = default);
#endregion
#region Permissions
/// <summary>
/// Responds to a permission request.
/// </summary>
/// <param name="sessionId">The session ID.</param>
/// <param name="permissionId">The permission ID.</param>
/// <param name="response">The permission response (allow/deny).</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task RespondToPermissionAsync(string sessionId, string permissionId, PermissionResponse response, string? directory = null, CancellationToken cancellationToken = default);
#endregion
#region Files
/// <summary>
/// Lists files in a directory.
/// </summary>
/// <param name="path">The path to list.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="FileNode"/> instances.</returns>
Task<List<FileNode>> ListFilesAsync(string path, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Reads the content of a file.
/// </summary>
/// <param name="path">The file path.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The <see cref="FileContent"/>.</returns>
Task<FileContent> ReadFileAsync(string path, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets file status (modified, added, deleted files).
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The <see cref="FileStatus"/>.</returns>
Task<FileStatus> GetFileStatusAsync(string? directory = null, CancellationToken cancellationToken = default);
#endregion
#region Find
/// <summary>
/// Searches for text in files.
/// </summary>
/// <param name="query">The search query.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>Search results as a list of strings.</returns>
Task<List<string>> FindTextAsync(string query, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Searches for files by name/pattern.
/// </summary>
/// <param name="query">The search query.</param>
/// <param name="dirs">Optional directories to search in.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of matching file paths.</returns>
Task<List<string>> FindFilesAsync(string query, string? dirs = null, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Searches for symbols in code.
/// </summary>
/// <param name="query">The symbol search query.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="Symbol"/> instances.</returns>
Task<List<Symbol>> FindSymbolsAsync(string query, string? directory = null, CancellationToken cancellationToken = default);
#endregion
#region PTY (Pseudo-Terminal)
/// <summary>
/// Lists all PTY instances.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="Pty"/> instances.</returns>
Task<List<Pty>> ListPtysAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new PTY.
/// </summary>
/// <param name="request">The PTY creation request.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The created <see cref="Pty"/>.</returns>
Task<Pty> CreatePtyAsync(CreatePtyRequest request, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets a PTY by ID.
/// </summary>
/// <param name="ptyId">The PTY ID.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The <see cref="Pty"/>.</returns>
Task<Pty> GetPtyAsync(string ptyId, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Updates a PTY (e.g., changes title).
/// </summary>
/// <param name="ptyId">The PTY ID.</param>
/// <param name="request">The update request.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The updated <see cref="Pty"/>.</returns>
Task<Pty> UpdatePtyAsync(string ptyId, UpdatePtyRequest request, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Deletes a PTY.
/// </summary>
/// <param name="ptyId">The PTY ID to delete.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task DeletePtyAsync(string ptyId, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Connects to a PTY for reading/writing (returns a WebSocket-like stream).
/// </summary>
/// <param name="ptyId">The PTY ID.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>An async enumerable of output data.</returns>
IAsyncEnumerable<string> ConnectToPtyAsync(string ptyId, string? directory = null, CancellationToken cancellationToken = default);
#endregion
#region MCP (Model Context Protocol)
/// <summary>
/// Gets the status of all MCP servers.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="McpStatus"/> instances.</returns>
Task<List<McpStatus>> GetMcpStatusAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Adds a new MCP server.
/// </summary>
/// <param name="request">The MCP server configuration.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task AddMcpServerAsync(AddMcpServerRequest request, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Starts authentication for an MCP server.
/// </summary>
/// <param name="name">The MCP server name.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task StartMcpAuthAsync(string name, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Removes authentication for an MCP server.
/// </summary>
/// <param name="name">The MCP server name.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task RemoveMcpAuthAsync(string name, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Authenticates an MCP server.
/// </summary>
/// <param name="name">The MCP server name.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task AuthenticateMcpAsync(string name, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Handles OAuth callback for MCP server authentication.
/// </summary>
/// <param name="name">The MCP server name.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task HandleMcpAuthCallbackAsync(string name, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Connects to an MCP server.
/// </summary>
/// <param name="name">The MCP server name.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task ConnectMcpAsync(string name, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Disconnects from an MCP server.
/// </summary>
/// <param name="name">The MCP server name.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task DisconnectMcpAsync(string name, string? directory = null, CancellationToken cancellationToken = default);
#endregion
#region Configuration
/// <summary>
/// Gets the OpenCode configuration.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The configuration as a dictionary.</returns>
Task<Dictionary<string, object>> GetConfigAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Updates the OpenCode configuration.
/// </summary>
/// <param name="config">The configuration updates.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task UpdateConfigAsync(Dictionary<string, object> config, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets available provider configurations.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A dictionary of provider configurations.</returns>
Task<Dictionary<string, object>> GetConfigProvidersAsync(string? directory = null, CancellationToken cancellationToken = default);
#endregion
#region Providers
/// <summary>
/// Lists all available AI providers.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="Provider"/> instances.</returns>
Task<List<Provider>> ListProvidersAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets provider authentication information.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="ProviderAuth"/> instances.</returns>
Task<List<ProviderAuth>> GetProviderAuthAsync(string? directory = null, CancellationToken cancellationToken = default);
#endregion
#region Other Operations
/// <summary>
/// Gets a list of available agents.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="Agent"/> instances.</returns>
Task<List<Agent>> ListAgentsAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Lists available slash commands.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>A list of <see cref="Command"/> instances.</returns>
Task<List<Command>> ListCommandsAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets the LSP (Language Server Protocol) status.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The <see cref="LspStatus"/>.</returns>
Task<LspStatus> GetLspStatusAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets the formatter status.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The <see cref="FormatterStatus"/>.</returns>
Task<FormatterStatus> GetFormatterStatusAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets path information (cwd and root).
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The <see cref="PathInfo"/>.</returns>
Task<PathInfo> GetPathAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Gets version control system information.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>The <see cref="VcsInfo"/>.</returns>
Task<VcsInfo> GetVcsInfoAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Subscribes to events for a specific directory/instance.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>An async enumerable of <see cref="Event"/> instances.</returns>
IAsyncEnumerable<Event> SubscribeToEventsAsync(string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Subscribes to events with progress callbacks for UI scenarios.
/// </summary>
/// <param name="progress">Progress callback for streaming status updates.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>An async enumerable of <see cref="Event"/> instances.</returns>
/// <remarks>
/// <para>
/// The progress callback receives <see cref="StreamingProgress"/> updates including:
/// </para>
/// <list type="bullet">
/// <item><description>Connection status (Starting, Connected, Receiving)</description></item>
/// <item><description>Chunk count and bytes received</description></item>
/// <item><description>Elapsed time</description></item>
/// <item><description>Error and cancellation notifications</description></item>
/// </list>
/// <para>
/// This is particularly useful for updating UI elements with streaming status.
/// </para>
/// </remarks>
/// <example>
/// <code>
/// var progress = new Progress<StreamingProgress>(p =>
/// {
/// Console.WriteLine($"Status: {p.Status}, Chunks: {p.ChunkCount}, Bytes: {p.BytesReceived}");
/// });
///
/// await foreach (var evt in client.SubscribeToEventsAsync(progress))
/// {
/// // Process event
/// }
/// </code>
/// </example>
IAsyncEnumerable<Event> SubscribeToEventsAsync(IProgress<StreamingProgress> progress, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Subscribes to events with progress callbacks and a custom timeout.
/// </summary>
/// <param name="progress">Progress callback for streaming status updates.</param>
/// <param name="timeout">The timeout for the streaming operation.</param>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
/// <returns>An async enumerable of <see cref="Event"/> instances.</returns>
/// <remarks>
/// Use this overload when you need to limit how long the event subscription should run.
/// After the timeout, the stream will complete gracefully.
/// </remarks>
IAsyncEnumerable<Event> SubscribeToEventsAsync(IProgress<StreamingProgress> progress, TimeSpan timeout, string? directory = null, CancellationToken cancellationToken = default);
/// <summary>
/// Disposes the current instance.
/// </summary>
/// <param name="directory">Optional directory context.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
Task DisposeInstanceAsync(string? directory = null, CancellationToken cancellationToken = default);
#endregion
}