@@ -1,1110 +0,0 @@
1−package soy.iko.opencode.core
2−
3−import com.novi.bincode.BincodeDeserializer
4−import com.novi.bincode.BincodeSerializer
5−import com.novi.serde.Bytes
6−import com.novi.serde.DeserializationError
7−import com.novi.serde.Deserializer
8−import com.novi.serde.Serializer
9−
10−fun <T> List<T>.serialize(
11− serializer: Serializer,
12− serializeElement: Serializer.(T) -> Unit,
13−) {
14− serializer.serialize_len(size.toLong())
15− forEach { element ->
16− serializer.serializeElement(element)
17− }
18−}
19−
20−fun <T> Deserializer.deserializeListOf(deserializeElement: (Deserializer) -> T): List<T> {
21− val length = deserialize_len()
22− val list = mutableListOf<T>()
23− repeat(length.toInt()) {
24− list.add(deserializeElement(this))
25− }
26− return list
27−}
28−
29−fun <T> T?.serializeOptionOf(
30− serializer: Serializer,
31− serializeElement: Serializer.(T) -> Unit,
32−) {
33− if (this != null) {
34− serializer.serialize_option_tag(true)
35− serializer.serializeElement(this)
36− } else {
37− serializer.serialize_option_tag(false)
38− }
39−}
40−
41−fun <T> Deserializer.deserializeOptionOf(deserializeElement: (Deserializer) -> T): T? {
42− val tag = deserialize_option_tag()
43− return if (tag) {
44− deserializeElement(this)
45− } else {
46− null
47− }
48−}
49−
50−sealed interface Effect {
51− fun serialize(serializer: Serializer)
52−
53− fun bincodeSerialize(): ByteArray {
54− val serializer = BincodeSerializer()
55− serialize(serializer)
56− return serializer.get_bytes()
57− }
58−
59− data class Render(
60− val value: soy.iko.opencode.core.RenderOperation,
61− ) : Effect {
62− override fun serialize(serializer: Serializer) {
63− serializer.increase_container_depth()
64− serializer.serialize_variant_index(0)
65− value.serialize(serializer)
66− serializer.decrease_container_depth()
67− }
68−
69− companion object {
70− fun deserialize(deserializer: Deserializer): Render {
71− deserializer.increase_container_depth()
72− val value = soy.iko.opencode.core.RenderOperation.deserialize(deserializer)
73− deserializer.decrease_container_depth()
74− return Render(value)
75− }
76− }
77− }
78−
79− data class Http(
80− val value: soy.iko.opencode.core.HttpRequest,
81− ) : Effect {
82− override fun serialize(serializer: Serializer) {
83− serializer.increase_container_depth()
84− serializer.serialize_variant_index(1)
85− value.serialize(serializer)
86− serializer.decrease_container_depth()
87− }
88−
89− companion object {
90− fun deserialize(deserializer: Deserializer): Http {
91− deserializer.increase_container_depth()
92− val value = soy.iko.opencode.core.HttpRequest.deserialize(deserializer)
93− deserializer.decrease_container_depth()
94− return Http(value)
95− }
96− }
97− }
98−
99− companion object {
100− @Throws(DeserializationError::class)
101− fun deserialize(deserializer: Deserializer): Effect {
102− val index = deserializer.deserialize_variant_index()
103− return when (index) {
104− 0 -> Render.deserialize(deserializer)
105− 1 -> Http.deserialize(deserializer)
106− else -> throw DeserializationError("Unknown variant index for Effect: $index")
107− }
108− }
109−
110− @Throws(DeserializationError::class)
111− fun bincodeDeserialize(input: ByteArray?): Effect {
112− if (input == null) {
113− throw DeserializationError("Cannot deserialize null array")
114− }
115− val deserializer = BincodeDeserializer(input)
116− val value = deserialize(deserializer)
117− if (deserializer.get_buffer_offset() < input.size) {
118− throw DeserializationError("Some input bytes were not read")
119− }
120− return value
121− }
122− }
123−}
124−
125−sealed interface Event {
126− fun serialize(serializer: Serializer)
127−
128− fun bincodeSerialize(): ByteArray {
129− val serializer = BincodeSerializer()
130− serialize(serializer)
131− return serializer.get_bytes()
132− }
133−
134− data object Start: Event {
135− override fun serialize(serializer: Serializer) {
136− serializer.increase_container_depth()
137− serializer.serialize_variant_index(0)
138− serializer.decrease_container_depth()
139− }
140−
141− fun deserialize(deserializer: Deserializer): Start {
142− return Start
143− }
144− }
145−
146− data class ServerUrlChanged(
147− val value: String,
148− ) : Event {
149− override fun serialize(serializer: Serializer) {
150− serializer.increase_container_depth()
151− serializer.serialize_variant_index(1)
152− serializer.serialize_str(value)
153− serializer.decrease_container_depth()
154− }
155−
156− companion object {
157− fun deserialize(deserializer: Deserializer): ServerUrlChanged {
158− deserializer.increase_container_depth()
159− val value = deserializer.deserialize_str()
160− deserializer.decrease_container_depth()
161− return ServerUrlChanged(value)
162− }
163− }
164− }
165−
166− data object Connect: Event {
167− override fun serialize(serializer: Serializer) {
168− serializer.increase_container_depth()
169− serializer.serialize_variant_index(2)
170− serializer.decrease_container_depth()
171− }
172−
173− fun deserialize(deserializer: Deserializer): Connect {
174− return Connect
175− }
176− }
177−
178− data object LoadSessions: Event {
179− override fun serialize(serializer: Serializer) {
180− serializer.increase_container_depth()
181− serializer.serialize_variant_index(3)
182− serializer.decrease_container_depth()
183− }
184−
185− fun deserialize(deserializer: Deserializer): LoadSessions {
186− return LoadSessions
187− }
188− }
189−
190− data class SelectSession(
191− val value: String,
192− ) : Event {
193− override fun serialize(serializer: Serializer) {
194− serializer.increase_container_depth()
195− serializer.serialize_variant_index(4)
196− serializer.serialize_str(value)
197− serializer.decrease_container_depth()
198− }
199−
200− companion object {
201− fun deserialize(deserializer: Deserializer): SelectSession {
202− deserializer.increase_container_depth()
203− val value = deserializer.deserialize_str()
204− deserializer.decrease_container_depth()
205− return SelectSession(value)
206− }
207− }
208− }
209−
210− data object CreateSession: Event {
211− override fun serialize(serializer: Serializer) {
212− serializer.increase_container_depth()
213− serializer.serialize_variant_index(5)
214− serializer.decrease_container_depth()
215− }
216−
217− fun deserialize(deserializer: Deserializer): CreateSession {
218− return CreateSession
219− }
220− }
221−
222− data object SessionCreated: Event {
223− override fun serialize(serializer: Serializer) {
224− serializer.increase_container_depth()
225− serializer.serialize_variant_index(6)
226− serializer.decrease_container_depth()
227− }
228−
229− fun deserialize(deserializer: Deserializer): SessionCreated {
230− return SessionCreated
231− }
232− }
233−
234− data class LoadMessages(
235− val value: String,
236− ) : Event {
237− override fun serialize(serializer: Serializer) {
238− serializer.increase_container_depth()
239− serializer.serialize_variant_index(7)
240− serializer.serialize_str(value)
241− serializer.decrease_container_depth()
242− }
243−
244− companion object {
245− fun deserialize(deserializer: Deserializer): LoadMessages {
246− deserializer.increase_container_depth()
247− val value = deserializer.deserialize_str()
248− deserializer.decrease_container_depth()
249− return LoadMessages(value)
250− }
251− }
252− }
253−
254− data object MessagesLoaded: Event {
255− override fun serialize(serializer: Serializer) {
256− serializer.increase_container_depth()
257− serializer.serialize_variant_index(8)
258− serializer.decrease_container_depth()
259− }
260−
261− fun deserialize(deserializer: Deserializer): MessagesLoaded {
262− return MessagesLoaded
263− }
264− }
265−
266− data class SendMessage(
267− val value: String,
268− ) : Event {
269− override fun serialize(serializer: Serializer) {
270− serializer.increase_container_depth()
271− serializer.serialize_variant_index(9)
272− serializer.serialize_str(value)
273− serializer.decrease_container_depth()
274− }
275−
276− companion object {
277− fun deserialize(deserializer: Deserializer): SendMessage {
278− deserializer.increase_container_depth()
279− val value = deserializer.deserialize_str()
280− deserializer.decrease_container_depth()
281− return SendMessage(value)
282− }
283− }
284− }
285−
286− data object MessageSent: Event {
287− override fun serialize(serializer: Serializer) {
288− serializer.increase_container_depth()
289− serializer.serialize_variant_index(10)
290− serializer.decrease_container_depth()
291− }
292−
293− fun deserialize(deserializer: Deserializer): MessageSent {
294− return MessageSent
295− }
296− }
297−
298− data class EventReceived(
299− val value: String,
300− ) : Event {
301− override fun serialize(serializer: Serializer) {
302− serializer.increase_container_depth()
303− serializer.serialize_variant_index(11)
304− serializer.serialize_str(value)
305− serializer.decrease_container_depth()
306− }
307−
308− companion object {
309− fun deserialize(deserializer: Deserializer): EventReceived {
310− deserializer.increase_container_depth()
311− val value = deserializer.deserialize_str()
312− deserializer.decrease_container_depth()
313− return EventReceived(value)
314− }
315− }
316− }
317−
318− data class NavigateToChat(
319− val value: String,
320− ) : Event {
321− override fun serialize(serializer: Serializer) {
322− serializer.increase_container_depth()
323− serializer.serialize_variant_index(12)
324− serializer.serialize_str(value)
325− serializer.decrease_container_depth()
326− }
327−
328− companion object {
329− fun deserialize(deserializer: Deserializer): NavigateToChat {
330− deserializer.increase_container_depth()
331− val value = deserializer.deserialize_str()
332− deserializer.decrease_container_depth()
333− return NavigateToChat(value)
334− }
335− }
336− }
337−
338− data object NavigateToSessions: Event {
339− override fun serialize(serializer: Serializer) {
340− serializer.increase_container_depth()
341− serializer.serialize_variant_index(13)
342− serializer.decrease_container_depth()
343− }
344−
345− fun deserialize(deserializer: Deserializer): NavigateToSessions {
346− return NavigateToSessions
347− }
348− }
349−
350− data object DismissError: Event {
351− override fun serialize(serializer: Serializer) {
352− serializer.increase_container_depth()
353− serializer.serialize_variant_index(14)
354− serializer.decrease_container_depth()
355− }
356−
357− fun deserialize(deserializer: Deserializer): DismissError {
358− return DismissError
359− }
360− }
361−
362− companion object {
363− @Throws(DeserializationError::class)
364− fun deserialize(deserializer: Deserializer): Event {
365− val index = deserializer.deserialize_variant_index()
366− return when (index) {
367− 0 -> Start.deserialize(deserializer)
368− 1 -> ServerUrlChanged.deserialize(deserializer)
369− 2 -> Connect.deserialize(deserializer)
370− 3 -> LoadSessions.deserialize(deserializer)
371− 4 -> SelectSession.deserialize(deserializer)
372− 5 -> CreateSession.deserialize(deserializer)
373− 6 -> SessionCreated.deserialize(deserializer)
374− 7 -> LoadMessages.deserialize(deserializer)
375− 8 -> MessagesLoaded.deserialize(deserializer)
376− 9 -> SendMessage.deserialize(deserializer)
377− 10 -> MessageSent.deserialize(deserializer)
378− 11 -> EventReceived.deserialize(deserializer)
379− 12 -> NavigateToChat.deserialize(deserializer)
380− 13 -> NavigateToSessions.deserialize(deserializer)
381− 14 -> DismissError.deserialize(deserializer)
382− else -> throw DeserializationError("Unknown variant index for Event: $index")
383− }
384− }
385−
386− @Throws(DeserializationError::class)
387− fun bincodeDeserialize(input: ByteArray?): Event {
388− if (input == null) {
389− throw DeserializationError("Cannot deserialize null array")
390− }
391− val deserializer = BincodeDeserializer(input)
392− val value = deserialize(deserializer)
393− if (deserializer.get_buffer_offset() < input.size) {
394− throw DeserializationError("Some input bytes were not read")
395− }
396− return value
397− }
398− }
399−}
400−
401−/// An error produced when an HTTP request fails.
402−///
403−/// Variants fall into two groups:
404−///
405−/// **Transport errors** — generated by the shell when it cannot complete the HTTP
406−/// exchange. These cross the FFI boundary and are serialized in the protocol:
407−/// [`Url`](HttpError::Url), [`Io`](HttpError::Io), [`Timeout`](HttpError::Timeout).
408−///
409−/// **Processing errors** — generated on the Rust side after a response arrives.
410−/// These are never serialized or visible to shells:
411−///
412−/// - [`Http`](HttpError::Http) — produced by `Response::new()` when the server returns
413−/// a 4xx or 5xx status. At the *protocol* level these arrive as
414−/// [`HttpResult::Ok`](crate::protocol::HttpResult::Ok); `Response::new()` converts
415−/// them here, so app code using `crux_http::Result<Response<T>>` will see them as
416−/// `Err(HttpError::Http { code, .. })`.
417−/// - [`Json`](HttpError::Json) — produced when response body deserialisation fails.
418−sealed interface HttpError {
419− fun serialize(serializer: Serializer)
420−
421− fun bincodeSerialize(): ByteArray {
422− val serializer = BincodeSerializer()
423− serialize(serializer)
424− return serializer.get_bytes()
425− }
426−
427− /// The request URL could not be parsed.
428− data class Url(
429− val value: String,
430− ) : HttpError {
431− override fun serialize(serializer: Serializer) {
432− serializer.increase_container_depth()
433− serializer.serialize_variant_index(0)
434− serializer.serialize_str(value)
435− serializer.decrease_container_depth()
436− }
437−
438− companion object {
439− fun deserialize(deserializer: Deserializer): Url {
440− deserializer.increase_container_depth()
441− val value = deserializer.deserialize_str()
442− deserializer.decrease_container_depth()
443− return Url(value)
444− }
445− }
446− }
447−
448− /// An IO error prevented the request from completing.
449− data class Io(
450− val value: String,
451− ) : HttpError {
452− override fun serialize(serializer: Serializer) {
453− serializer.increase_container_depth()
454− serializer.serialize_variant_index(1)
455− serializer.serialize_str(value)
456− serializer.decrease_container_depth()
457− }
458−
459− companion object {
460− fun deserialize(deserializer: Deserializer): Io {
461− deserializer.increase_container_depth()
462− val value = deserializer.deserialize_str()
463− deserializer.decrease_container_depth()
464− return Io(value)
465− }
466− }
467− }
468−
469− /// The request timed out before a response was received.
470− data object Timeout: HttpError {
471− override fun serialize(serializer: Serializer) {
472− serializer.increase_container_depth()
473− serializer.serialize_variant_index(2)
474− serializer.decrease_container_depth()
475− }
476−
477− fun deserialize(deserializer: Deserializer): Timeout {
478− return Timeout
479− }
480− }
481−
482− companion object {
483− @Throws(DeserializationError::class)
484− fun deserialize(deserializer: Deserializer): HttpError {
485− val index = deserializer.deserialize_variant_index()
486− return when (index) {
487− 0 -> Url.deserialize(deserializer)
488− 1 -> Io.deserialize(deserializer)
489− 2 -> Timeout.deserialize(deserializer)
490− else -> throw DeserializationError("Unknown variant index for HttpError: $index")
491− }
492− }
493−
494− @Throws(DeserializationError::class)
495− fun bincodeDeserialize(input: ByteArray?): HttpError {
496− if (input == null) {
497− throw DeserializationError("Cannot deserialize null array")
498− }
499− val deserializer = BincodeDeserializer(input)
500− val value = deserialize(deserializer)
501− if (deserializer.get_buffer_offset() < input.size) {
502− throw DeserializationError("Some input bytes were not read")
503− }
504− return value
505− }
506− }
507−}
508−
509−data class HttpHeader(
510− val name: String,
511− val value: String,
512−) {
513− fun serialize(serializer: Serializer) {
514− serializer.increase_container_depth()
515− serializer.serialize_str(name)
516− serializer.serialize_str(value)
517− serializer.decrease_container_depth()
518− }
519−
520− fun bincodeSerialize(): ByteArray {
521− val serializer = BincodeSerializer()
522− serialize(serializer)
523− return serializer.get_bytes()
524− }
525−
526− companion object {
527− fun deserialize(deserializer: Deserializer): HttpHeader {
528− deserializer.increase_container_depth()
529− val name = deserializer.deserialize_str()
530− val value = deserializer.deserialize_str()
531− deserializer.decrease_container_depth()
532− return HttpHeader(name, value)
533− }
534−
535− @Throws(DeserializationError::class)
536− fun bincodeDeserialize(input: ByteArray?): HttpHeader {
537− if (input == null) {
538− throw DeserializationError("Cannot deserialize null array")
539− }
540− val deserializer = BincodeDeserializer(input)
541− val value = deserialize(deserializer)
542− if (deserializer.get_buffer_offset() < input.size) {
543− throw DeserializationError("Some input bytes were not read")
544− }
545− return value
546− }
547− }
548−}
549−
550−/// A raw HTTP request, as sent to the shell over the protocol boundary.
551−///
552−/// # No header validation
553−///
554−/// All fields are plain strings. Header names and values are carried as-is with no
555−/// validation against the HTTP specification. This is intentional: `HttpRequest` is a
556−/// cross-language data carrier deserialised by Swift, Kotlin, and TypeScript shells;
557−/// Rust's `http`-crate validation rules cannot be enforced on the other side of that
558−/// boundary.
559−///
560−/// **Shell authors must not assume that header names or values are well-formed.**
561−/// Pass them to your underlying HTTP client as-is — it will apply its own rules.
562−///
563−/// For the ergonomic Rust-side builder that *does* validate header values (and panics
564−/// on invalid input), see [`crate::command::RequestBuilder`].
565−data class HttpRequest(
566− val method: String,
567− val url: String,
568− val headers: List<soy.iko.opencode.core.HttpHeader>,
569− val body: Bytes,
570−) {
571− fun serialize(serializer: Serializer) {
572− serializer.increase_container_depth()
573− serializer.serialize_str(method)
574− serializer.serialize_str(url)
575− headers.serialize(serializer) {
576− it.serialize(serializer)
577− }
578− serializer.serialize_bytes(body)
579− serializer.decrease_container_depth()
580− }
581−
582− fun bincodeSerialize(): ByteArray {
583− val serializer = BincodeSerializer()
584− serialize(serializer)
585− return serializer.get_bytes()
586− }
587−
588− companion object {
589− fun deserialize(deserializer: Deserializer): HttpRequest {
590− deserializer.increase_container_depth()
591− val method = deserializer.deserialize_str()
592− val url = deserializer.deserialize_str()
593− val headers =
594− deserializer.deserializeListOf {
595− soy.iko.opencode.core.HttpHeader.deserialize(deserializer)
596− }
597− val body = deserializer.deserialize_bytes()
598− deserializer.decrease_container_depth()
599− return HttpRequest(method, url, headers, body)
600− }
601−
602− @Throws(DeserializationError::class)
603− fun bincodeDeserialize(input: ByteArray?): HttpRequest {
604− if (input == null) {
605− throw DeserializationError("Cannot deserialize null array")
606− }
607− val deserializer = BincodeDeserializer(input)
608− val value = deserialize(deserializer)
609− if (deserializer.get_buffer_offset() < input.size) {
610− throw DeserializationError("Some input bytes were not read")
611− }
612− return value
613− }
614− }
615−}
616−
617−data class HttpResponse(
618− val status: UShort,
619− val headers: List<soy.iko.opencode.core.HttpHeader>,
620− val body: Bytes,
621−) {
622− fun serialize(serializer: Serializer) {
623− serializer.increase_container_depth()
624− serializer.serialize_u16(status)
625− headers.serialize(serializer) {
626− it.serialize(serializer)
627− }
628− serializer.serialize_bytes(body)
629− serializer.decrease_container_depth()
630− }
631−
632− fun bincodeSerialize(): ByteArray {
633− val serializer = BincodeSerializer()
634− serialize(serializer)
635− return serializer.get_bytes()
636− }
637−
638− companion object {
639− fun deserialize(deserializer: Deserializer): HttpResponse {
640− deserializer.increase_container_depth()
641− val status = deserializer.deserialize_u16()
642− val headers =
643− deserializer.deserializeListOf {
644− soy.iko.opencode.core.HttpHeader.deserialize(deserializer)
645− }
646− val body = deserializer.deserialize_bytes()
647− deserializer.decrease_container_depth()
648− return HttpResponse(status, headers, body)
649− }
650−
651− @Throws(DeserializationError::class)
652− fun bincodeDeserialize(input: ByteArray?): HttpResponse {
653− if (input == null) {
654− throw DeserializationError("Cannot deserialize null array")
655− }
656− val deserializer = BincodeDeserializer(input)
657− val value = deserialize(deserializer)
658− if (deserializer.get_buffer_offset() < input.size) {
659− throw DeserializationError("Some input bytes were not read")
660− }
661− return value
662− }
663− }
664−}
665−
666−/// The result of an HTTP request, as returned by the shell over the protocol boundary.
667−///
668−/// # Status codes are not errors
669−///
670−/// Any completed HTTP exchange — including responses with 4xx or 5xx status codes — is
671−/// returned as [`HttpResult::Ok`]. Only *transport-level* failures (the shell could not
672−/// reach the server at all) produce [`HttpResult::Err`].
673−///
674−/// To act on an error status, inspect [`HttpResponse::status`]:
675−///
676−/// ```
677−/// # use crux_http::protocol::{HttpResult, HttpResponse};
678−/// # use crux_http::HttpError;
679−/// # fn handle(result: HttpResult) {
680−/// match result {
681−/// HttpResult::Ok(response) if response.status == 200 => { /* success */ }
682−/// HttpResult::Ok(response) if response.status == 404 => { /* not found */ }
683−/// HttpResult::Ok(response) if response.status >= 500 => { /* server error */ }
684−/// HttpResult::Ok(_) => { /* other status */ }
685−/// HttpResult::Err(e) => { /* transport failure: bad URL, IO error, or timeout */ }
686−/// }
687−/// # }
688−/// ```
689−sealed interface HttpResult {
690− fun serialize(serializer: Serializer)
691−
692− fun bincodeSerialize(): ByteArray {
693− val serializer = BincodeSerializer()
694− serialize(serializer)
695− return serializer.get_bytes()
696− }
697−
698− /// The shell completed the HTTP exchange. The response may carry any status code,
699− /// including 4xx and 5xx — inspect [`HttpResponse::status`] to distinguish them.
700− data class Ok(
701− val value: soy.iko.opencode.core.HttpResponse,
702− ) : HttpResult {
703− override fun serialize(serializer: Serializer) {
704− serializer.increase_container_depth()
705− serializer.serialize_variant_index(0)
706− value.serialize(serializer)
707− serializer.decrease_container_depth()
708− }
709−
710− companion object {
711− fun deserialize(deserializer: Deserializer): Ok {
712− deserializer.increase_container_depth()
713− val value = soy.iko.opencode.core.HttpResponse.deserialize(deserializer)
714− deserializer.decrease_container_depth()
715− return Ok(value)
716− }
717− }
718− }
719−
720− /// The shell could not complete the HTTP exchange due to a transport-level failure.
721− /// See [`HttpError`] for the possible causes.
722− data class Err(
723− val value: soy.iko.opencode.core.HttpError,
724− ) : HttpResult {
725− override fun serialize(serializer: Serializer) {
726− serializer.increase_container_depth()
727− serializer.serialize_variant_index(1)
728− value.serialize(serializer)
729− serializer.decrease_container_depth()
730− }
731−
732− companion object {
733− fun deserialize(deserializer: Deserializer): Err {
734− deserializer.increase_container_depth()
735− val value = soy.iko.opencode.core.HttpError.deserialize(deserializer)
736− deserializer.decrease_container_depth()
737− return Err(value)
738− }
739− }
740− }
741−
742− companion object {
743− @Throws(DeserializationError::class)
744− fun deserialize(deserializer: Deserializer): HttpResult {
745− val index = deserializer.deserialize_variant_index()
746− return when (index) {
747− 0 -> Ok.deserialize(deserializer)
748− 1 -> Err.deserialize(deserializer)
749− else -> throw DeserializationError("Unknown variant index for HttpResult: $index")
750− }
751− }
752−
753− @Throws(DeserializationError::class)
754− fun bincodeDeserialize(input: ByteArray?): HttpResult {
755− if (input == null) {
756− throw DeserializationError("Cannot deserialize null array")
757− }
758− val deserializer = BincodeDeserializer(input)
759− val value = deserialize(deserializer)
760− if (deserializer.get_buffer_offset() < input.size) {
761− throw DeserializationError("Some input bytes were not read")
762− }
763− return value
764− }
765− }
766−}
767−
768−data class MessageView(
769− val id: String,
770− val role: String,
771− val text: String,
772− val time: ULong,
773−) {
774− fun serialize(serializer: Serializer) {
775− serializer.increase_container_depth()
776− serializer.serialize_str(id)
777− serializer.serialize_str(role)
778− serializer.serialize_str(text)
779− serializer.serialize_u64(time)
780− serializer.decrease_container_depth()
781− }
782−
783− fun bincodeSerialize(): ByteArray {
784− val serializer = BincodeSerializer()
785− serialize(serializer)
786− return serializer.get_bytes()
787− }
788−
789− companion object {
790− fun deserialize(deserializer: Deserializer): MessageView {
791− deserializer.increase_container_depth()
792− val id = deserializer.deserialize_str()
793− val role = deserializer.deserialize_str()
794− val text = deserializer.deserialize_str()
795− val time = deserializer.deserialize_u64()
796− deserializer.decrease_container_depth()
797− return MessageView(id, role, text, time)
798− }
799−
800− @Throws(DeserializationError::class)
801− fun bincodeDeserialize(input: ByteArray?): MessageView {
802− if (input == null) {
803− throw DeserializationError("Cannot deserialize null array")
804− }
805− val deserializer = BincodeDeserializer(input)
806− val value = deserialize(deserializer)
807− if (deserializer.get_buffer_offset() < input.size) {
808− throw DeserializationError("Some input bytes were not read")
809− }
810− return value
811− }
812− }
813−}
814−
815−/// The single operation `Render` implements.
816−data object RenderOperation {
817− fun serialize(serializer: Serializer) {}
818−
819− fun bincodeSerialize(): ByteArray {
820− val serializer = BincodeSerializer()
821− serialize(serializer)
822− return serializer.get_bytes()
823− }
824−
825− fun deserialize(deserializer: Deserializer): RenderOperation {
826− return RenderOperation
827− }
828−
829− @Throws(DeserializationError::class)
830− fun bincodeDeserialize(input: ByteArray?): RenderOperation {
831− if (input == null) {
832− throw DeserializationError("Cannot deserialize null array")
833− }
834− val deserializer = BincodeDeserializer(input)
835− val value = deserialize(deserializer)
836− if (deserializer.get_buffer_offset() < input.size) {
837− throw DeserializationError("Some input bytes were not read")
838− }
839− return value
840− }
841−}
842−
843−/// Request for a side-effect passed from the Core to the Shell.
844−///
845−/// The `EffectId` links the `Request` with the corresponding call to [`Core::resolve`] to pass the data back
846−/// to the [`App::update`] function (wrapped in the event provided to the capability originating the effect).
847−data class Request(
848− val id: UInt,
849− val effect: soy.iko.opencode.core.Effect,
850−) {
851− fun serialize(serializer: Serializer) {
852− serializer.increase_container_depth()
853− serializer.serialize_u32(id)
854− effect.serialize(serializer)
855− serializer.decrease_container_depth()
856− }
857−
858− fun bincodeSerialize(): ByteArray {
859− val serializer = BincodeSerializer()
860− serialize(serializer)
861− return serializer.get_bytes()
862− }
863−
864− companion object {
865− fun deserialize(deserializer: Deserializer): Request {
866− deserializer.increase_container_depth()
867− val id = deserializer.deserialize_u32()
868− val effect = soy.iko.opencode.core.Effect.deserialize(deserializer)
869− deserializer.decrease_container_depth()
870− return Request(id, effect)
871− }
872−
873− @Throws(DeserializationError::class)
874− fun bincodeDeserialize(input: ByteArray?): Request {
875− if (input == null) {
876− throw DeserializationError("Cannot deserialize null array")
877− }
878− val deserializer = BincodeDeserializer(input)
879− val value = deserialize(deserializer)
880− if (deserializer.get_buffer_offset() < input.size) {
881− throw DeserializationError("Some input bytes were not read")
882− }
883− return value
884− }
885− }
886−}
887−
888−/// A batch of effect requests from the Core to the Shell, as serialised by
889−/// [`Bridge::update`] and [`Bridge::resolve`].
890−///
891−/// The wire format is identical to `Vec<Request<Eff>>` (the newtype is
892−/// `serde(transparent)`), so existing shell code that already deserialises
893−/// a `Vec<Request>` remains binary-compatible.
894−///
895−/// Registering this type with the type-generation system causes the code
896−/// generators to emit a `Requests` type (with a `value` field containing the
897−/// list) together with a top-level `bincodeDeserialize` / `BincodeDeserialize`
898−/// helper, replacing the hand-written extension files that were previously
899−/// appended by `add_extensions()`.
900−data class Requests(
901− val value: List<soy.iko.opencode.core.Request>,
902−) {
903− fun serialize(serializer: Serializer) {
904− serializer.increase_container_depth()
905− value.serialize(serializer) {
906− it.serialize(serializer)
907− }
908− serializer.decrease_container_depth()
909− }
910−
911− fun bincodeSerialize(): ByteArray {
912− val serializer = BincodeSerializer()
913− serialize(serializer)
914− return serializer.get_bytes()
915− }
916−
917− companion object {
918− fun deserialize(deserializer: Deserializer): Requests {
919− deserializer.increase_container_depth()
920− val value =
921− deserializer.deserializeListOf {
922− soy.iko.opencode.core.Request.deserialize(deserializer)
923− }
924− deserializer.decrease_container_depth()
925− return Requests(value)
926− }
927−
928− @Throws(DeserializationError::class)
929− fun bincodeDeserialize(input: ByteArray?): Requests {
930− if (input == null) {
931− throw DeserializationError("Cannot deserialize null array")
932− }
933− val deserializer = BincodeDeserializer(input)
934− val value = deserialize(deserializer)
935− if (deserializer.get_buffer_offset() < input.size) {
936− throw DeserializationError("Some input bytes were not read")
937− }
938− return value
939− }
940− }
941−}
942−
943−enum class Screen {
944− CONNECT,
945− SESSIONS,
946− CHAT;
947−
948− fun serialize(serializer: Serializer) {
949− serializer.increase_container_depth()
950− serializer.serialize_variant_index(ordinal)
951− serializer.decrease_container_depth()
952− }
953−
954− fun bincodeSerialize(): ByteArray {
955− val serializer = BincodeSerializer()
956− serialize(serializer)
957− return serializer.get_bytes()
958− }
959−
960− companion object {
961− @Throws(DeserializationError::class)
962− fun deserialize(deserializer: Deserializer): Screen {
963− deserializer.increase_container_depth()
964− val index = deserializer.deserialize_variant_index()
965− deserializer.decrease_container_depth()
966− return when (index) {
967− 0 -> CONNECT
968− 1 -> SESSIONS
969− 2 -> CHAT
970− else -> throw DeserializationError("Unknown variant index for Screen: $index")
971− }
972− }
973−
974− @Throws(DeserializationError::class)
975− fun bincodeDeserialize(input: ByteArray?): Screen {
976− if (input == null) {
977− throw DeserializationError("Cannot deserialize null array")
978− }
979− val deserializer = BincodeDeserializer(input)
980− val value = deserialize(deserializer)
981− if (deserializer.get_buffer_offset() < input.size) {
982− throw DeserializationError("Some input bytes were not read")
983− }
984− return value
985− }
986− }
987−}
988−
989−data class SessionView(
990− val id: String,
991− val title: String,
992−) {
993− fun serialize(serializer: Serializer) {
994− serializer.increase_container_depth()
995− serializer.serialize_str(id)
996− serializer.serialize_str(title)
997− serializer.decrease_container_depth()
998− }
999−
1000− fun bincodeSerialize(): ByteArray {
1001− val serializer = BincodeSerializer()
1002− serialize(serializer)
1003− return serializer.get_bytes()
1004− }
1005−
1006− companion object {
1007− fun deserialize(deserializer: Deserializer): SessionView {
1008− deserializer.increase_container_depth()
1009− val id = deserializer.deserialize_str()
1010− val title = deserializer.deserialize_str()
1011− deserializer.decrease_container_depth()
1012− return SessionView(id, title)
1013− }
1014−
1015− @Throws(DeserializationError::class)
1016− fun bincodeDeserialize(input: ByteArray?): SessionView {
1017− if (input == null) {
1018− throw DeserializationError("Cannot deserialize null array")
1019− }
1020− val deserializer = BincodeDeserializer(input)
1021− val value = deserialize(deserializer)
1022− if (deserializer.get_buffer_offset() < input.size) {
1023− throw DeserializationError("Some input bytes were not read")
1024− }
1025− return value
1026− }
1027− }
1028−}
1029−
1030−data class ViewModel(
1031− val screen: soy.iko.opencode.core.Screen,
1032− val serverUrl: String,
1033− val connected: Boolean,
1034− val loading: Boolean,
1035− val error: String? = null,
1036− val sessions: List<soy.iko.opencode.core.SessionView>,
1037− val currentSessionId: String? = null,
1038− val messages: List<soy.iko.opencode.core.MessageView>,
1039− val draftMessage: String,
1040−) {
1041− fun serialize(serializer: Serializer) {
1042− serializer.increase_container_depth()
1043− screen.serialize(serializer)
1044− serializer.serialize_str(serverUrl)
1045− serializer.serialize_bool(connected)
1046− serializer.serialize_bool(loading)
1047− error.serializeOptionOf(serializer) {
1048− serializer.serialize_str(it)
1049− }
1050− sessions.serialize(serializer) {
1051− it.serialize(serializer)
1052− }
1053− currentSessionId.serializeOptionOf(serializer) {
1054− serializer.serialize_str(it)
1055− }
1056− messages.serialize(serializer) {
1057− it.serialize(serializer)
1058− }
1059− serializer.serialize_str(draftMessage)
1060− serializer.decrease_container_depth()
1061− }
1062−
1063− fun bincodeSerialize(): ByteArray {
1064− val serializer = BincodeSerializer()
1065− serialize(serializer)
1066− return serializer.get_bytes()
1067− }
1068−
1069− companion object {
1070− fun deserialize(deserializer: Deserializer): ViewModel {
1071− deserializer.increase_container_depth()
1072− val screen = soy.iko.opencode.core.Screen.deserialize(deserializer)
1073− val serverUrl = deserializer.deserialize_str()
1074− val connected = deserializer.deserialize_bool()
1075− val loading = deserializer.deserialize_bool()
1076− val error =
1077− deserializer.deserializeOptionOf {
1078− deserializer.deserialize_str()
1079− }
1080− val sessions =
1081− deserializer.deserializeListOf {
1082− soy.iko.opencode.core.SessionView.deserialize(deserializer)
1083− }
1084− val currentSessionId =
1085− deserializer.deserializeOptionOf {
1086− deserializer.deserialize_str()
1087− }
1088− val messages =
1089− deserializer.deserializeListOf {
1090− soy.iko.opencode.core.MessageView.deserialize(deserializer)
1091− }
1092− val draftMessage = deserializer.deserialize_str()
1093− deserializer.decrease_container_depth()
1094− return ViewModel(screen, serverUrl, connected, loading, error, sessions, currentSessionId, messages, draftMessage)
1095− }
1096−
1097− @Throws(DeserializationError::class)
1098− fun bincodeDeserialize(input: ByteArray?): ViewModel {
1099− if (input == null) {
1100− throw DeserializationError("Cannot deserialize null array")
1101− }
1102− val deserializer = BincodeDeserializer(input)
1103− val value = deserialize(deserializer)
1104− if (deserializer.get_buffer_offset() < input.size) {
1105− throw DeserializationError("Some input bytes were not read")
1106− }
1107− return value
1108− }
1109− }
1110−}