@pocketcoder/shared 0.0.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 (67) hide show
  1. package/LICENSE +53 -0
  2. package/dist/constants/__tests__/limits.test.d.ts +2 -0
  3. package/dist/constants/__tests__/limits.test.d.ts.map +1 -0
  4. package/dist/constants/__tests__/limits.test.js +68 -0
  5. package/dist/constants/__tests__/limits.test.js.map +1 -0
  6. package/dist/constants/errors.d.ts +48 -0
  7. package/dist/constants/errors.d.ts.map +1 -0
  8. package/dist/constants/errors.js +61 -0
  9. package/dist/constants/errors.js.map +1 -0
  10. package/dist/constants/index.d.ts +3 -0
  11. package/dist/constants/index.d.ts.map +1 -0
  12. package/dist/constants/index.js +4 -0
  13. package/dist/constants/index.js.map +1 -0
  14. package/dist/constants/limits.d.ts +41 -0
  15. package/dist/constants/limits.d.ts.map +1 -0
  16. package/dist/constants/limits.js +46 -0
  17. package/dist/constants/limits.js.map +1 -0
  18. package/dist/index.d.ts +3 -0
  19. package/dist/index.d.ts.map +1 -0
  20. package/dist/index.js +4 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/types/__tests__/auth-messages.test.d.ts +2 -0
  23. package/dist/types/__tests__/auth-messages.test.d.ts.map +1 -0
  24. package/dist/types/__tests__/auth-messages.test.js +94 -0
  25. package/dist/types/__tests__/auth-messages.test.js.map +1 -0
  26. package/dist/types/__tests__/messages.test.d.ts +2 -0
  27. package/dist/types/__tests__/messages.test.d.ts.map +1 -0
  28. package/dist/types/__tests__/messages.test.js +329 -0
  29. package/dist/types/__tests__/messages.test.js.map +1 -0
  30. package/dist/types/__tests__/relay-types.test.d.ts +2 -0
  31. package/dist/types/__tests__/relay-types.test.d.ts.map +1 -0
  32. package/dist/types/__tests__/relay-types.test.js +69 -0
  33. package/dist/types/__tests__/relay-types.test.js.map +1 -0
  34. package/dist/types/auth-messages.d.ts +49 -0
  35. package/dist/types/auth-messages.d.ts.map +1 -0
  36. package/dist/types/auth-messages.js +9 -0
  37. package/dist/types/auth-messages.js.map +1 -0
  38. package/dist/types/database.d.ts +259 -0
  39. package/dist/types/database.d.ts.map +1 -0
  40. package/dist/types/database.js +6 -0
  41. package/dist/types/database.js.map +1 -0
  42. package/dist/types/index.d.ts +5 -0
  43. package/dist/types/index.d.ts.map +1 -0
  44. package/dist/types/index.js +6 -0
  45. package/dist/types/index.js.map +1 -0
  46. package/dist/types/messages.d.ts +821 -0
  47. package/dist/types/messages.d.ts.map +1 -0
  48. package/dist/types/messages.js +122 -0
  49. package/dist/types/messages.js.map +1 -0
  50. package/dist/types/relay.d.ts +62 -0
  51. package/dist/types/relay.d.ts.map +1 -0
  52. package/dist/types/relay.js +8 -0
  53. package/dist/types/relay.js.map +1 -0
  54. package/package.json +49 -0
  55. package/src/constants/__tests__/limits.test.ts +93 -0
  56. package/src/constants/errors.ts +71 -0
  57. package/src/constants/index.ts +3 -0
  58. package/src/constants/limits.ts +53 -0
  59. package/src/index.ts +3 -0
  60. package/src/types/__tests__/auth-messages.test.ts +108 -0
  61. package/src/types/__tests__/messages.test.ts +382 -0
  62. package/src/types/__tests__/relay-types.test.ts +82 -0
  63. package/src/types/auth-messages.ts +66 -0
  64. package/src/types/database.ts +320 -0
  65. package/src/types/index.ts +5 -0
  66. package/src/types/messages.ts +1310 -0
  67. package/src/types/relay.ts +79 -0
@@ -0,0 +1,1310 @@
1
+ /**
2
+ * WebSocket message types for communication between daemon, relay, and client.
3
+ * All types match the PRD exactly.
4
+ */
5
+
6
+ // ---------------------------------------------------------------------------
7
+ // Shared primitives
8
+ // ---------------------------------------------------------------------------
9
+
10
+ /** All known message type strings */
11
+ export type MessageType =
12
+ // Filesystem
13
+ | "fs_list"
14
+ | "fs_list_response"
15
+ | "fs_read"
16
+ | "fs_read_response"
17
+ | "fs_write"
18
+ | "fs_write_response"
19
+ | "fs_create"
20
+ | "fs_create_response"
21
+ | "fs_delete"
22
+ | "fs_delete_response"
23
+ | "fs_search"
24
+ | "fs_search_response"
25
+ | "fs_replace"
26
+ | "fs_replace_response"
27
+ | "fs_changed"
28
+ // Git
29
+ | "git_status"
30
+ | "git_status_response"
31
+ | "git_branches"
32
+ | "git_branches_response"
33
+ | "git_branch_create"
34
+ | "git_branch_create_response"
35
+ | "git_checkout"
36
+ | "git_checkout_response"
37
+ | "git_stage"
38
+ | "git_stage_response"
39
+ | "git_unstage"
40
+ | "git_unstage_response"
41
+ | "git_commit"
42
+ | "git_commit_response"
43
+ | "git_push"
44
+ | "git_push_response"
45
+ | "git_pull"
46
+ | "git_pull_response"
47
+ | "git_file_base"
48
+ | "git_file_base_response"
49
+ | "git_discard"
50
+ | "git_discard_response"
51
+ | "git_diff"
52
+ | "git_diff_response"
53
+ // Commands
54
+ | "command_exec"
55
+ | "command_output"
56
+ | "command_exit"
57
+ | "command_cancel"
58
+ // Terminal
59
+ | "terminal_create"
60
+ | "terminal_create_response"
61
+ | "terminal_stdin"
62
+ | "terminal_stdout"
63
+ | "terminal_resize"
64
+ | "terminal_kill"
65
+ | "terminal_exit"
66
+ // Agent / Claude
67
+ | "agent_sessions_list"
68
+ | "agent_sessions_list_response"
69
+ | "agent_session_new"
70
+ | "agent_session_new_response"
71
+ | "agent_message"
72
+ | "agent_message_response"
73
+ | "agent_event"
74
+ | "agent_cancel"
75
+ | "agent_prompt_response"
76
+ // Discovery
77
+ | "daemon_register"
78
+ | "project_added"
79
+ | "project_removed"
80
+ | "machines_list"
81
+ | "machines_list_response"
82
+ | "projects_list"
83
+ | "projects_list_response"
84
+ | "project_create"
85
+ | "project_create_response"
86
+ | "project_delete"
87
+ | "project_delete_response"
88
+ // Credentials (git push/pull)
89
+ | "credential_prompt"
90
+ | "credential_response"
91
+ // OpenCode SSE
92
+ | "sse_event"
93
+ // OpenCode permission
94
+ | "permission_reply"
95
+ | "permission_reply_response"
96
+ // Generic
97
+ | "error";
98
+
99
+ // ---------------------------------------------------------------------------
100
+ // Error format (shared across all error responses)
101
+ // ---------------------------------------------------------------------------
102
+
103
+ export interface MessageError {
104
+ code: string;
105
+ message: string;
106
+ details?: Record<string, unknown>;
107
+ }
108
+
109
+ // ---------------------------------------------------------------------------
110
+ // Filesystem types
111
+ // ---------------------------------------------------------------------------
112
+
113
+ export interface FsNode {
114
+ name: string;
115
+ path: string; // Relative to project
116
+ type: "file" | "dir";
117
+ size?: number; // Only for files
118
+ mtime?: string; // ISO 8601
119
+ children?: FsNode[]; // Only if expanded
120
+ expanded?: boolean;
121
+ }
122
+
123
+ export interface FsChange {
124
+ kind: "create" | "modify" | "delete";
125
+ path: string;
126
+ }
127
+
128
+ // -- fs_list --
129
+
130
+ export interface FsListRequest {
131
+ type: "fs_list";
132
+ requestId: string;
133
+ sessionId: string;
134
+ payload: {
135
+ path: string; // Relative path, '' for root
136
+ depth?: number; // Default 1
137
+ };
138
+ }
139
+
140
+ export interface FsListResponse {
141
+ type: "fs_list_response";
142
+ requestId: string;
143
+ sessionId: string;
144
+ payload?: {
145
+ path: string;
146
+ children: FsNode[];
147
+ seq: number;
148
+ };
149
+ error?: MessageError;
150
+ }
151
+
152
+ // -- fs_read --
153
+
154
+ export interface FsReadRequest {
155
+ type: "fs_read";
156
+ requestId: string;
157
+ sessionId: string;
158
+ payload: {
159
+ path: string;
160
+ };
161
+ }
162
+
163
+ export interface FsReadResponse {
164
+ type: "fs_read_response";
165
+ requestId: string;
166
+ payload?: {
167
+ path: string;
168
+ content: string;
169
+ encoding: string;
170
+ size: number;
171
+ mtime: string;
172
+ };
173
+ error?: MessageError;
174
+ }
175
+
176
+ // -- fs_write --
177
+
178
+ export interface FsWriteRequest {
179
+ type: "fs_write";
180
+ requestId: string;
181
+ sessionId: string;
182
+ payload: {
183
+ path: string;
184
+ content: string;
185
+ createDirs?: boolean; // Default true
186
+ };
187
+ }
188
+
189
+ export interface FsWriteResponse {
190
+ type: "fs_write_response";
191
+ requestId: string;
192
+ payload?: {
193
+ path: string;
194
+ size: number;
195
+ mtime: string;
196
+ };
197
+ error?: MessageError;
198
+ }
199
+
200
+ // -- fs_create --
201
+
202
+ export interface FsCreateRequest {
203
+ type: "fs_create";
204
+ requestId: string;
205
+ sessionId: string;
206
+ payload: {
207
+ path: string;
208
+ itemType: "file" | "directory";
209
+ createDirs?: boolean; // Default true
210
+ };
211
+ }
212
+
213
+ export interface FsCreateResponse {
214
+ type: "fs_create_response";
215
+ requestId: string;
216
+ payload?: {
217
+ path: string;
218
+ itemType: "file" | "directory";
219
+ };
220
+ error?: MessageError;
221
+ }
222
+
223
+ // -- fs_delete --
224
+
225
+ export interface FsDeleteRequest {
226
+ type: "fs_delete";
227
+ requestId: string;
228
+ sessionId: string;
229
+ payload: {
230
+ path: string;
231
+ };
232
+ }
233
+
234
+ export interface FsDeleteResponse {
235
+ type: "fs_delete_response";
236
+ requestId: string;
237
+ payload?: {
238
+ path: string;
239
+ };
240
+ error?: MessageError;
241
+ }
242
+
243
+ // -- fs_search --
244
+
245
+ export interface FsSearchMatch {
246
+ line: number;
247
+ content: string;
248
+ column?: number;
249
+ }
250
+
251
+ export interface FsSearchFileResult {
252
+ path: string;
253
+ matches: FsSearchMatch[];
254
+ }
255
+
256
+ export interface FsSearchRequest {
257
+ type: "fs_search";
258
+ requestId: string;
259
+ sessionId: string;
260
+ payload: {
261
+ query: string;
262
+ glob?: string; // Optional file pattern filter
263
+ caseSensitive?: boolean; // Default false
264
+ regex?: boolean; // Default false
265
+ };
266
+ }
267
+
268
+ export interface FsSearchResponse {
269
+ type: "fs_search_response";
270
+ requestId: string;
271
+ payload?: {
272
+ query: string;
273
+ totalMatches: number;
274
+ truncated: boolean;
275
+ files: FsSearchFileResult[];
276
+ };
277
+ error?: MessageError;
278
+ }
279
+
280
+ // -- fs_replace --
281
+
282
+ export interface FsReplaceFileResult {
283
+ path: string;
284
+ replacements: number;
285
+ }
286
+
287
+ export interface FsReplaceRequest {
288
+ type: "fs_replace";
289
+ requestId: string;
290
+ sessionId: string;
291
+ payload: {
292
+ find: string;
293
+ replace: string;
294
+ glob?: string; // Optional file pattern filter
295
+ caseSensitive?: boolean; // Default false
296
+ regex?: boolean; // Default false
297
+ };
298
+ }
299
+
300
+ export interface FsReplaceResponse {
301
+ type: "fs_replace_response";
302
+ requestId: string;
303
+ payload?: {
304
+ totalReplacements: number;
305
+ filesModified: FsReplaceFileResult[];
306
+ };
307
+ error?: MessageError;
308
+ }
309
+
310
+ // -- fs_changed (push event, no requestId) --
311
+
312
+ export interface FsChangedEvent {
313
+ type: "fs_changed";
314
+ sessionId: string;
315
+ payload: {
316
+ seq: number;
317
+ changes: FsChange[];
318
+ changesTruncated?: boolean;
319
+ };
320
+ }
321
+
322
+ // ---------------------------------------------------------------------------
323
+ // Git types
324
+ // ---------------------------------------------------------------------------
325
+
326
+ export interface GitFileStatus {
327
+ path: string;
328
+ status: string;
329
+ }
330
+
331
+ export interface GitBranch {
332
+ name: string;
333
+ remote: string | null;
334
+ ahead: number;
335
+ behind: number;
336
+ }
337
+
338
+ // -- git_status --
339
+
340
+ export interface GitStatusRequest {
341
+ type: "git_status";
342
+ requestId: string;
343
+ sessionId: string;
344
+ payload: Record<string, never>;
345
+ }
346
+
347
+ export interface GitStatusResponse {
348
+ type: "git_status_response";
349
+ requestId: string;
350
+ payload?: {
351
+ branch: string;
352
+ clean: boolean;
353
+ staged: GitFileStatus[];
354
+ unstaged: GitFileStatus[];
355
+ conflicts: GitFileStatus[];
356
+ };
357
+ error?: MessageError;
358
+ }
359
+
360
+ // -- git_branches --
361
+
362
+ export interface GitBranchesRequest {
363
+ type: "git_branches";
364
+ requestId: string;
365
+ sessionId: string;
366
+ payload: Record<string, never>;
367
+ }
368
+
369
+ export interface GitBranchesResponse {
370
+ type: "git_branches_response";
371
+ requestId: string;
372
+ payload?: {
373
+ current: string;
374
+ branches: GitBranch[];
375
+ };
376
+ error?: MessageError;
377
+ }
378
+
379
+ // -- git_branch_create --
380
+
381
+ export interface GitBranchCreateRequest {
382
+ type: "git_branch_create";
383
+ requestId: string;
384
+ sessionId: string;
385
+ payload: {
386
+ name: string;
387
+ startPoint?: string; // Default HEAD
388
+ };
389
+ }
390
+
391
+ export interface GitBranchCreateResponse {
392
+ type: "git_branch_create_response";
393
+ requestId: string;
394
+ payload?: {
395
+ name: string;
396
+ created: boolean;
397
+ };
398
+ error?: MessageError;
399
+ }
400
+
401
+ // -- git_checkout --
402
+
403
+ export interface GitCheckoutRequest {
404
+ type: "git_checkout";
405
+ requestId: string;
406
+ sessionId: string;
407
+ payload: {
408
+ ref: string;
409
+ };
410
+ }
411
+
412
+ export interface GitCheckoutResponse {
413
+ type: "git_checkout_response";
414
+ requestId: string;
415
+ payload?: {
416
+ ref: string;
417
+ switched: boolean;
418
+ };
419
+ error?: MessageError;
420
+ }
421
+
422
+ // -- git_stage --
423
+
424
+ export interface GitStageRequest {
425
+ type: "git_stage";
426
+ requestId: string;
427
+ sessionId: string;
428
+ payload: {
429
+ paths: string[];
430
+ };
431
+ }
432
+
433
+ export interface GitStageResponse {
434
+ type: "git_stage_response";
435
+ requestId: string;
436
+ payload?: {
437
+ staged: string[];
438
+ };
439
+ error?: MessageError;
440
+ }
441
+
442
+ // -- git_unstage --
443
+
444
+ export interface GitUnstageRequest {
445
+ type: "git_unstage";
446
+ requestId: string;
447
+ sessionId: string;
448
+ payload: {
449
+ paths: string[];
450
+ };
451
+ }
452
+
453
+ export interface GitUnstageResponse {
454
+ type: "git_unstage_response";
455
+ requestId: string;
456
+ payload?: {
457
+ unstaged: string[];
458
+ };
459
+ error?: MessageError;
460
+ }
461
+
462
+ // -- git_commit --
463
+
464
+ export interface GitCommitRequest {
465
+ type: "git_commit";
466
+ requestId: string;
467
+ sessionId: string;
468
+ payload: {
469
+ message: string;
470
+ };
471
+ }
472
+
473
+ export interface GitCommitResponse {
474
+ type: "git_commit_response";
475
+ requestId: string;
476
+ payload?: {
477
+ sha: string;
478
+ message: string;
479
+ };
480
+ error?: MessageError;
481
+ }
482
+
483
+ // -- git_push --
484
+
485
+ export interface GitPushRequest {
486
+ type: "git_push";
487
+ requestId: string;
488
+ sessionId: string;
489
+ payload: {
490
+ remote?: string; // Default origin
491
+ branch?: string; // Default current branch
492
+ force?: boolean; // Default false
493
+ };
494
+ }
495
+
496
+ export interface GitPushResponse {
497
+ type: "git_push_response";
498
+ requestId: string;
499
+ payload?: {
500
+ remote: string;
501
+ branch: string;
502
+ pushed: boolean;
503
+ };
504
+ error?: MessageError;
505
+ }
506
+
507
+ // -- git_pull --
508
+
509
+ export interface GitPullRequest {
510
+ type: "git_pull";
511
+ requestId: string;
512
+ sessionId: string;
513
+ payload: {
514
+ remote?: string; // Default origin
515
+ branch?: string; // Default current branch
516
+ };
517
+ }
518
+
519
+ export interface GitPullResponse {
520
+ type: "git_pull_response";
521
+ requestId: string;
522
+ payload?: {
523
+ remote: string;
524
+ branch: string;
525
+ pulled: boolean;
526
+ conflicts?: string[];
527
+ };
528
+ error?: MessageError;
529
+ }
530
+
531
+ // -- git_file_base --
532
+
533
+ export interface GitFileBaseRequest {
534
+ type: "git_file_base";
535
+ requestId: string;
536
+ sessionId: string;
537
+ payload: {
538
+ path: string;
539
+ ref?: string; // Default HEAD
540
+ };
541
+ }
542
+
543
+ export interface GitFileBaseResponse {
544
+ type: "git_file_base_response";
545
+ requestId: string;
546
+ payload?: {
547
+ path: string;
548
+ ref: string;
549
+ content: string | null; // null if file is new
550
+ };
551
+ error?: MessageError;
552
+ }
553
+
554
+ // -- git_discard --
555
+
556
+ export interface GitDiscardRequest {
557
+ type: "git_discard";
558
+ requestId: string;
559
+ sessionId: string;
560
+ payload: {
561
+ paths?: string[]; // Specific files to discard; omit or empty for all
562
+ all?: boolean; // Discard all changes (tracked + untracked)
563
+ };
564
+ }
565
+
566
+ export interface GitDiscardResponse {
567
+ type: "git_discard_response";
568
+ requestId: string;
569
+ payload?: {
570
+ discarded: number; // Count of discarded files
571
+ };
572
+ error?: MessageError;
573
+ }
574
+
575
+ // -- git_diff --
576
+
577
+ export interface GitDiffRequest {
578
+ type: "git_diff";
579
+ requestId: string;
580
+ sessionId: string;
581
+ payload: {
582
+ path?: string; // Specific file; omit for all
583
+ staged?: boolean; // Default false
584
+ };
585
+ }
586
+
587
+ export interface GitDiffFileResult {
588
+ path: string;
589
+ status: string; // added, modified, deleted
590
+ additions: number;
591
+ deletions: number;
592
+ diff: string;
593
+ }
594
+
595
+ export interface GitDiffResponse {
596
+ type: "git_diff_response";
597
+ requestId: string;
598
+ payload?: {
599
+ files: GitDiffFileResult[];
600
+ };
601
+ error?: MessageError;
602
+ }
603
+
604
+ // -- credential_prompt (host → client, during git push/pull) --
605
+
606
+ export type CredentialPromptType = "password" | "passphrase" | "username" | "pin";
607
+
608
+ export interface CredentialPromptEvent {
609
+ type: "credential_prompt";
610
+ requestId: string;
611
+ payload: {
612
+ promptType: CredentialPromptType;
613
+ prompt: string;
614
+ };
615
+ }
616
+
617
+ // -- credential_response (client → host) --
618
+
619
+ export interface CredentialResponseRequest {
620
+ type: "credential_response";
621
+ requestId: string;
622
+ payload: {
623
+ value: string;
624
+ cancelled: boolean;
625
+ };
626
+ }
627
+
628
+ // -- sse_event (OpenCode SSE events forwarded through tunnel) --
629
+
630
+ export interface SseEventMessage {
631
+ type: "sse_event";
632
+ payload: {
633
+ event: string;
634
+ data: string;
635
+ sessionId?: string;
636
+ };
637
+ }
638
+
639
+ // -- permission_reply (forward permission reply to OpenCode) --
640
+
641
+ export type PermissionReplyValue = "once" | "always" | "reject";
642
+
643
+ export interface PermissionReplyRequest {
644
+ type: "permission_reply";
645
+ requestId: string;
646
+ sessionId: string;
647
+ payload: {
648
+ permissionId: string;
649
+ reply: PermissionReplyValue;
650
+ };
651
+ }
652
+
653
+ export interface PermissionReplyResponse {
654
+ type: "permission_reply_response";
655
+ requestId: string;
656
+ payload?: {
657
+ status: number;
658
+ body?: unknown;
659
+ };
660
+ error?: MessageError;
661
+ }
662
+
663
+ // ---------------------------------------------------------------------------
664
+ // Command types
665
+ // ---------------------------------------------------------------------------
666
+
667
+ // -- command_exec --
668
+
669
+ export interface CommandExecRequest {
670
+ type: "command_exec";
671
+ requestId: string;
672
+ sessionId: string;
673
+ payload: {
674
+ command: string;
675
+ };
676
+ }
677
+
678
+ export interface CommandOutputEvent {
679
+ type: "command_output";
680
+ requestId: string;
681
+ payload: {
682
+ stdoutChunk?: string;
683
+ stderrChunk?: string;
684
+ };
685
+ }
686
+
687
+ export interface CommandExitEvent {
688
+ type: "command_exit";
689
+ requestId: string;
690
+ payload: {
691
+ exitCode: number | null; // null if cancelled/killed
692
+ signal?: string;
693
+ durationMs: number;
694
+ };
695
+ }
696
+
697
+ // -- command_cancel --
698
+
699
+ export interface CommandCancelRequest {
700
+ type: "command_cancel";
701
+ requestId: string;
702
+ sessionId: string;
703
+ payload: {
704
+ requestId: string; // ID of command to cancel
705
+ };
706
+ }
707
+
708
+ // ---------------------------------------------------------------------------
709
+ // Terminal types
710
+ // ---------------------------------------------------------------------------
711
+
712
+ // -- terminal_create --
713
+
714
+ export interface TerminalCreateRequest {
715
+ type: "terminal_create";
716
+ requestId: string;
717
+ sessionId: string;
718
+ payload: {
719
+ cols?: number;
720
+ rows?: number;
721
+ };
722
+ }
723
+
724
+ export interface TerminalCreateResponse {
725
+ type: "terminal_create_response";
726
+ requestId: string;
727
+ payload: {
728
+ terminalId: string;
729
+ };
730
+ error?: MessageError;
731
+ }
732
+
733
+ // -- terminal_stdin --
734
+
735
+ export interface TerminalStdinRequest {
736
+ type: "terminal_stdin";
737
+ requestId: string;
738
+ sessionId: string;
739
+ payload: {
740
+ terminalId: string;
741
+ data: string;
742
+ };
743
+ }
744
+
745
+ // -- terminal_stdout --
746
+
747
+ export interface TerminalStdoutEvent {
748
+ type: "terminal_stdout";
749
+ payload: {
750
+ terminalId: string;
751
+ data: string;
752
+ };
753
+ }
754
+
755
+ // -- terminal_resize --
756
+
757
+ export interface TerminalResizeRequest {
758
+ type: "terminal_resize";
759
+ requestId: string;
760
+ sessionId: string;
761
+ payload: {
762
+ terminalId: string;
763
+ cols: number;
764
+ rows: number;
765
+ };
766
+ }
767
+
768
+ // -- terminal_kill --
769
+
770
+ export interface TerminalKillRequest {
771
+ type: "terminal_kill";
772
+ requestId: string;
773
+ sessionId: string;
774
+ payload: {
775
+ terminalId: string;
776
+ };
777
+ }
778
+
779
+ // -- terminal_exit --
780
+
781
+ export interface TerminalExitEvent {
782
+ type: "terminal_exit";
783
+ payload: {
784
+ terminalId: string;
785
+ exitCode: number;
786
+ signal?: number;
787
+ };
788
+ }
789
+
790
+ // ---------------------------------------------------------------------------
791
+ // Agent / Claude types
792
+ // ---------------------------------------------------------------------------
793
+
794
+ export type AgentEvent =
795
+ | { type: "init"; sessionId: string; tools: string[]; model: string }
796
+ | { type: "thinking"; content: string }
797
+ | { type: "text"; content: string }
798
+ | { type: "tool_use"; tool: string; input: Record<string, unknown> }
799
+ | { type: "tool_complete"; toolUseId: string }
800
+ | { type: "file_edit"; path: string; diff?: string }
801
+ | { type: "file_create"; path: string }
802
+ | { type: "file_delete"; path: string }
803
+ | {
804
+ type: "prompt";
805
+ questions: Array<{
806
+ question: string;
807
+ header: string;
808
+ options: Array<{ label: string; description: string }>;
809
+ multiSelect: boolean;
810
+ }>;
811
+ }
812
+ | {
813
+ type: "done";
814
+ usage?: { input_tokens: number; output_tokens: number };
815
+ cancelled?: boolean;
816
+ error?: string;
817
+ };
818
+
819
+ export interface AgentSessionInfo {
820
+ agentSessionId: string;
821
+ lastUsedAt: string;
822
+ title: string | null;
823
+ }
824
+
825
+ // -- agent_sessions_list --
826
+
827
+ export interface AgentSessionsListRequest {
828
+ type: "agent_sessions_list";
829
+ requestId: string;
830
+ sessionId: string;
831
+ payload: Record<string, never>;
832
+ }
833
+
834
+ export interface AgentSessionsListResponse {
835
+ type: "agent_sessions_list_response";
836
+ requestId: string;
837
+ payload?: {
838
+ sessions: AgentSessionInfo[];
839
+ };
840
+ error?: MessageError;
841
+ }
842
+
843
+ // -- agent_session_new --
844
+
845
+ export interface AgentSessionNewRequest {
846
+ type: "agent_session_new";
847
+ requestId: string;
848
+ sessionId: string;
849
+ payload: {
850
+ content: string;
851
+ };
852
+ }
853
+
854
+ export interface AgentSessionNewResponse {
855
+ type: "agent_session_new_response";
856
+ requestId: string;
857
+ payload?: {
858
+ agentSessionId: string;
859
+ };
860
+ error?: MessageError;
861
+ }
862
+
863
+ // -- agent_message --
864
+
865
+ export interface AgentMessageRequest {
866
+ type: "agent_message";
867
+ requestId: string;
868
+ sessionId: string;
869
+ payload: {
870
+ agentSessionId: string;
871
+ content: string;
872
+ };
873
+ }
874
+
875
+ export interface AgentMessageResponse {
876
+ type: "agent_message_response";
877
+ requestId: string;
878
+ payload?: {
879
+ queued?: boolean;
880
+ started?: boolean;
881
+ };
882
+ error?: MessageError;
883
+ }
884
+
885
+ // -- agent_event (push, multiple during execution) --
886
+
887
+ export interface AgentEventMessage {
888
+ type: "agent_event";
889
+ sessionId: string;
890
+ payload: {
891
+ agentSessionId: string;
892
+ event: AgentEvent;
893
+ };
894
+ }
895
+
896
+ // -- agent_cancel --
897
+
898
+ export interface AgentCancelRequest {
899
+ type: "agent_cancel";
900
+ requestId: string;
901
+ sessionId: string;
902
+ payload: {
903
+ agentSessionId: string;
904
+ };
905
+ }
906
+
907
+ // -- agent_prompt_response --
908
+
909
+ export interface AgentPromptResponseRequest {
910
+ type: "agent_prompt_response";
911
+ requestId: string;
912
+ sessionId: string;
913
+ payload: {
914
+ agentSessionId: string;
915
+ response: string;
916
+ };
917
+ }
918
+
919
+ // ---------------------------------------------------------------------------
920
+ // Discovery types
921
+ // ---------------------------------------------------------------------------
922
+
923
+ export interface MachineMetadata {
924
+ os: "darwin" | "linux" | "win32";
925
+ osVersion: string;
926
+ hostname: string;
927
+ username: string;
928
+ label: string | null;
929
+ }
930
+
931
+ export interface RegisterProject {
932
+ projectId: string;
933
+ name: string;
934
+ path?: string; // Absolute path (for Host reference only)
935
+ }
936
+
937
+ // -- daemon_register (daemon → relay, no requestId) --
938
+
939
+ export interface DaemonRegisterMessage {
940
+ type: "daemon_register";
941
+ payload: {
942
+ machineKey: string;
943
+ token: string;
944
+ machine: MachineMetadata;
945
+ projects: RegisterProject[];
946
+ };
947
+ }
948
+
949
+ // -- project_added (daemon → relay, no requestId) --
950
+
951
+ export interface ProjectAddedMessage {
952
+ type: "project_added";
953
+ payload: {
954
+ projectId: string;
955
+ name: string;
956
+ path: string;
957
+ };
958
+ }
959
+
960
+ // -- project_removed (daemon → relay, no requestId) --
961
+
962
+ export interface ProjectRemovedMessage {
963
+ type: "project_removed";
964
+ payload: {
965
+ projectId: string;
966
+ };
967
+ }
968
+
969
+ // -- machines_list --
970
+
971
+ export interface MachinesListRequest {
972
+ type: "machines_list";
973
+ requestId: string;
974
+ payload: Record<string, never>;
975
+ }
976
+
977
+ export interface MachineInfo {
978
+ machineKey: string;
979
+ label: string;
980
+ os: string;
981
+ osVersion: string;
982
+ username: string;
983
+ online: boolean;
984
+ lastSeen: string;
985
+ projectCount: number;
986
+ }
987
+
988
+ export interface MachinesListResponse {
989
+ type: "machines_list_response";
990
+ requestId: string;
991
+ payload?: {
992
+ machines: MachineInfo[];
993
+ };
994
+ error?: MessageError;
995
+ }
996
+
997
+ // -- projects_list --
998
+
999
+ export interface ProjectsListRequest {
1000
+ type: "projects_list";
1001
+ requestId: string;
1002
+ payload: {
1003
+ machineKey: string;
1004
+ };
1005
+ }
1006
+
1007
+ export interface ProjectInfo {
1008
+ projectId: string;
1009
+ name: string;
1010
+ path: string;
1011
+ hasActiveSession: boolean;
1012
+ lastAccessed: string;
1013
+ }
1014
+
1015
+ export interface ProjectsListResponse {
1016
+ type: "projects_list_response";
1017
+ requestId: string;
1018
+ payload?: {
1019
+ projects: ProjectInfo[];
1020
+ };
1021
+ error?: MessageError;
1022
+ }
1023
+
1024
+ // -- project_create (client → daemon, creates a new project) --
1025
+
1026
+ export interface ProjectCreateRequest {
1027
+ type: "project_create";
1028
+ requestId: string;
1029
+ payload: {
1030
+ path: string;
1031
+ };
1032
+ }
1033
+
1034
+ export interface ProjectCreateResponse {
1035
+ type: "project_create_response";
1036
+ requestId: string;
1037
+ payload?: {
1038
+ project: {
1039
+ projectId: string;
1040
+ name: string;
1041
+ path: string;
1042
+ };
1043
+ };
1044
+ error?: MessageError;
1045
+ }
1046
+
1047
+ // -- project_delete (client → daemon, deletes a project) --
1048
+
1049
+ export interface ProjectDeleteRequest {
1050
+ type: "project_delete";
1051
+ requestId: string;
1052
+ payload: {
1053
+ projectId: string;
1054
+ };
1055
+ }
1056
+
1057
+ export interface ProjectDeleteResponse {
1058
+ type: "project_delete_response";
1059
+ requestId: string;
1060
+ payload?: {
1061
+ success: boolean;
1062
+ };
1063
+ error?: MessageError;
1064
+ }
1065
+
1066
+ // ---------------------------------------------------------------------------
1067
+ // Generic error response
1068
+ // ---------------------------------------------------------------------------
1069
+
1070
+ export interface ErrorResponse {
1071
+ type: "error";
1072
+ requestId: string;
1073
+ error: MessageError;
1074
+ }
1075
+
1076
+ // ---------------------------------------------------------------------------
1077
+ // Union of all messages
1078
+ // ---------------------------------------------------------------------------
1079
+
1080
+ export type RequestMessage =
1081
+ | FsListRequest
1082
+ | FsReadRequest
1083
+ | FsWriteRequest
1084
+ | FsCreateRequest
1085
+ | FsDeleteRequest
1086
+ | FsSearchRequest
1087
+ | FsReplaceRequest
1088
+ | GitStatusRequest
1089
+ | GitBranchesRequest
1090
+ | GitBranchCreateRequest
1091
+ | GitCheckoutRequest
1092
+ | GitStageRequest
1093
+ | GitUnstageRequest
1094
+ | GitCommitRequest
1095
+ | GitPushRequest
1096
+ | GitPullRequest
1097
+ | GitFileBaseRequest
1098
+ | GitDiscardRequest
1099
+ | GitDiffRequest
1100
+ | CommandExecRequest
1101
+ | CommandCancelRequest
1102
+ | TerminalCreateRequest
1103
+ | TerminalStdinRequest
1104
+ | TerminalResizeRequest
1105
+ | TerminalKillRequest
1106
+ | AgentSessionsListRequest
1107
+ | AgentSessionNewRequest
1108
+ | AgentMessageRequest
1109
+ | AgentCancelRequest
1110
+ | AgentPromptResponseRequest
1111
+ | MachinesListRequest
1112
+ | ProjectsListRequest
1113
+ | ProjectCreateRequest
1114
+ | ProjectDeleteRequest
1115
+ | CredentialResponseRequest
1116
+ | PermissionReplyRequest;
1117
+
1118
+ export type ResponseMessage =
1119
+ | FsListResponse
1120
+ | FsReadResponse
1121
+ | FsWriteResponse
1122
+ | FsCreateResponse
1123
+ | FsDeleteResponse
1124
+ | FsSearchResponse
1125
+ | FsReplaceResponse
1126
+ | GitStatusResponse
1127
+ | GitBranchesResponse
1128
+ | GitBranchCreateResponse
1129
+ | GitCheckoutResponse
1130
+ | GitStageResponse
1131
+ | GitUnstageResponse
1132
+ | GitCommitResponse
1133
+ | GitPushResponse
1134
+ | GitPullResponse
1135
+ | GitFileBaseResponse
1136
+ | GitDiscardResponse
1137
+ | GitDiffResponse
1138
+ | AgentSessionsListResponse
1139
+ | AgentSessionNewResponse
1140
+ | AgentMessageResponse
1141
+ | MachinesListResponse
1142
+ | ProjectsListResponse
1143
+ | ProjectCreateResponse
1144
+ | ProjectDeleteResponse
1145
+ | TerminalCreateResponse
1146
+ | PermissionReplyResponse
1147
+ | ErrorResponse;
1148
+
1149
+ export type EventMessage =
1150
+ | FsChangedEvent
1151
+ | CommandOutputEvent
1152
+ | TerminalStdoutEvent
1153
+ | TerminalExitEvent
1154
+ | CommandExitEvent
1155
+ | AgentEventMessage
1156
+ | CredentialPromptEvent
1157
+ | SseEventMessage;
1158
+
1159
+ export type Message =
1160
+ | RequestMessage
1161
+ | ResponseMessage
1162
+ | EventMessage
1163
+ | DaemonRegisterMessage
1164
+ | ProjectAddedMessage
1165
+ | ProjectRemovedMessage;
1166
+
1167
+ // ---------------------------------------------------------------------------
1168
+ // Type guards
1169
+ // ---------------------------------------------------------------------------
1170
+
1171
+ function isObject(value: unknown): value is Record<string, unknown> {
1172
+ return typeof value === "object" && value !== null;
1173
+ }
1174
+
1175
+ function hasType(value: unknown): value is { type: string } {
1176
+ return isObject(value) && typeof value.type === "string";
1177
+ }
1178
+
1179
+ function hasRequestId(value: unknown): value is { requestId: string } {
1180
+ return isObject(value) && typeof value.requestId === "string";
1181
+ }
1182
+
1183
+ function hasSessionId(value: unknown): value is { sessionId: string } {
1184
+ return isObject(value) && typeof value.sessionId === "string";
1185
+ }
1186
+
1187
+ function hasPayload(value: unknown): value is { payload: Record<string, unknown> } {
1188
+ return isObject(value) && isObject((value as Record<string, unknown>).payload);
1189
+ }
1190
+
1191
+ /** Validate that value looks like an fs_list request */
1192
+ export function isFsListRequest(value: unknown): value is FsListRequest {
1193
+ return (
1194
+ hasType(value) &&
1195
+ value.type === "fs_list" &&
1196
+ hasRequestId(value) &&
1197
+ hasSessionId(value) &&
1198
+ hasPayload(value) &&
1199
+ typeof (value as FsListRequest).payload.path === "string"
1200
+ );
1201
+ }
1202
+
1203
+ /** Validate that value looks like an fs_read request */
1204
+ export function isFsReadRequest(value: unknown): value is FsReadRequest {
1205
+ return (
1206
+ hasType(value) &&
1207
+ value.type === "fs_read" &&
1208
+ hasRequestId(value) &&
1209
+ hasSessionId(value) &&
1210
+ hasPayload(value) &&
1211
+ typeof (value as FsReadRequest).payload.path === "string"
1212
+ );
1213
+ }
1214
+
1215
+ /** Validate that value looks like a git_status request */
1216
+ export function isGitStatusRequest(value: unknown): value is GitStatusRequest {
1217
+ return (
1218
+ hasType(value) && value.type === "git_status" && hasRequestId(value) && hasSessionId(value)
1219
+ );
1220
+ }
1221
+
1222
+ /** Validate that value looks like an agent_message request */
1223
+ export function isAgentMessageRequest(value: unknown): value is AgentMessageRequest {
1224
+ return (
1225
+ hasType(value) &&
1226
+ value.type === "agent_message" &&
1227
+ hasRequestId(value) &&
1228
+ hasSessionId(value) &&
1229
+ hasPayload(value) &&
1230
+ typeof (value as AgentMessageRequest).payload.agentSessionId === "string" &&
1231
+ typeof (value as AgentMessageRequest).payload.content === "string"
1232
+ );
1233
+ }
1234
+
1235
+ /** Validate that value looks like an error response */
1236
+ export function isErrorResponse(value: unknown): value is ErrorResponse {
1237
+ if (!hasType(value) || value.type !== "error" || !hasRequestId(value)) {
1238
+ return false;
1239
+ }
1240
+ const v = value as Record<string, unknown>;
1241
+ return isObject(v.error) && typeof (v.error as Record<string, unknown>).code === "string";
1242
+ }
1243
+
1244
+ /** Validate that value is a valid message (has at least a type field) */
1245
+ export function isMessage(value: unknown): value is Message {
1246
+ return hasType(value);
1247
+ }
1248
+
1249
+ /** Validate that value is a request message (has type, requestId, and usually sessionId) */
1250
+ export function isRequestMessage(value: unknown): value is RequestMessage {
1251
+ return hasType(value) && hasRequestId(value);
1252
+ }
1253
+
1254
+ /** Validate that value is an AgentEvent with type 'init' */
1255
+ export function isAgentInitEvent(value: unknown): value is Extract<AgentEvent, { type: "init" }> {
1256
+ return (
1257
+ isObject(value) &&
1258
+ (value as Record<string, unknown>).type === "init" &&
1259
+ typeof (value as Record<string, unknown>).sessionId === "string" &&
1260
+ Array.isArray((value as Record<string, unknown>).tools) &&
1261
+ typeof (value as Record<string, unknown>).model === "string"
1262
+ );
1263
+ }
1264
+
1265
+ /** Validate that value is an AgentEvent with type 'done' */
1266
+ export function isAgentDoneEvent(value: unknown): value is Extract<AgentEvent, { type: "done" }> {
1267
+ if (!isObject(value) || (value as Record<string, unknown>).type !== "done") {
1268
+ return false;
1269
+ }
1270
+ const v = value as Record<string, unknown>;
1271
+ // usage is optional but must be correct shape if present
1272
+ if (v.usage !== undefined) {
1273
+ if (
1274
+ !isObject(v.usage) ||
1275
+ typeof (v.usage as Record<string, unknown>).input_tokens !== "number" ||
1276
+ typeof (v.usage as Record<string, unknown>).output_tokens !== "number"
1277
+ ) {
1278
+ return false;
1279
+ }
1280
+ }
1281
+ // error is optional but must be string if present
1282
+ if (v.error !== undefined && typeof v.error !== "string") {
1283
+ return false;
1284
+ }
1285
+ // cancelled is optional but must be boolean if present
1286
+ if (v.cancelled !== undefined && typeof v.cancelled !== "boolean") {
1287
+ return false;
1288
+ }
1289
+ return true;
1290
+ }
1291
+
1292
+ /** Validate that value is any valid AgentEvent (has a recognized type) */
1293
+ export function isAgentEvent(value: unknown): value is AgentEvent {
1294
+ if (!isObject(value) || typeof (value as Record<string, unknown>).type !== "string") {
1295
+ return false;
1296
+ }
1297
+ const validTypes = [
1298
+ "init",
1299
+ "thinking",
1300
+ "text",
1301
+ "tool_use",
1302
+ "tool_complete",
1303
+ "file_edit",
1304
+ "file_create",
1305
+ "file_delete",
1306
+ "prompt",
1307
+ "done",
1308
+ ];
1309
+ return validTypes.includes((value as Record<string, unknown>).type as string);
1310
+ }