opencode-ruby 0.0.1.alpha7 → 0.0.1.alpha8

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.

Potentially problematic release.


This version of opencode-ruby might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7a4ddecebacda21e25ac50bd14d6d36c8ad61b35d23dee985b620d82a2b94b36
4
- data.tar.gz: 3aa46267d464d9f95ddc96cb0a7d59cff04a9559c1dffb8d5c6d99c84f46b7b5
3
+ metadata.gz: dfc6ea6764466fdb7ba12492bd8b3d4ee7a1d69d8dd84e37f8f867341d785105
4
+ data.tar.gz: 91e656a98aafc77a861f06ba6f01a9b38a81b222abd5ef63d21d47a158ecef9b
5
5
  SHA512:
6
- metadata.gz: 2b7a4ef58b44d2d179c3dd389a0b3a2593557188fe03e62d8e63fa19b766de22f75cef35309f2155d3eb6af80bb79c4f44f3251448602aade9fc928761561a4e
7
- data.tar.gz: 141450c28378875563cb27742eea0ae60d08ef325c37b40923bb0b4103e26f9ce82dd603dc5db313578a12e8a7a160bbbea5aefdeed7e5f87751acb364410cd6
6
+ metadata.gz: 8e320bb05b4a39df6f6c70e2f0516fb2c7673b1724c1971b39688f90cd092606e458b04cc1c663dcbe000a0151f5db502900c6379ad265aeb64c3951ea7191a8
7
+ data.tar.gz: 50b9557c7ea186eba04687cbcd0219f66c8429645595d14897ccbd0aa4fc6b044a7b700148c65dd053cae89fd952e21f85ad4506aef9ca9f880d89e11d7f65b8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.0.1.alpha8 - 2026-07-20
4
+
5
+ ### Fixed
6
+
7
+ - Parse SSE events with CRLF, CR-only, or LF framing; accept `data:` fields
8
+ with or without the optional leading space; join multiple `data:` fields;
9
+ ignore the stream's optional leading UTF-8 BOM and comment fields; and decode
10
+ correctly when a transport chunk splits any byte of the event framing.
11
+
12
+ ### Changed
13
+
14
+ - Test Ruby 3.2, 3.3, 3.4, and 4.0; pin every third-party CI and release
15
+ action to an exact reviewed commit; and use Ruby 4.0 for release builds.
16
+ - Fail the trusted-publishing job before release when the pushed tag does not
17
+ match `Opencode::VERSION`.
18
+
3
19
  ## 0.0.1.alpha7 - 2026-07-18
4
20
 
5
21
  ### Fixed
@@ -100,5 +116,7 @@ First public alpha. HTTP + SSE client for OpenCode REST API.
100
116
  ### Compatibility
101
117
 
102
118
  - Ruby ≥ 3.2
103
- - OpenCode server 1.15 (tested against the message bus schema in `packages/opencode/src/session/message-v2.ts`)
119
+ - OpenCode targeted the then-current 1.15 message-bus shape. This historical
120
+ target was not a blanket SemVer compatibility guarantee; use the README's
121
+ current compatibility evidence for deployment decisions.
104
122
  - Runtime dependency: `activesupport (>= 6.1)` for `blank?`/`present?`/`presence`/`truncate`/`duplicable?`/`megabytes`. ActiveSupport is *not* Rails — it's a standalone helpers gem.
data/README.md CHANGED
@@ -67,7 +67,9 @@ child = client.create_session(
67
67
 
68
68
  Model strings use OpenCode's `provider/model` form; a preformatted model hash
69
69
  with `providerID` and `id` keys is also accepted. These configured-session
70
- fields require OpenCode 1.16.1 or newer.
70
+ fields first appeared in OpenCode 1.16.1. That is an API-introduction note,
71
+ not evidence that every later server is compatible; use the
72
+ [certified compatibility evidence](#compatibility) for deployment choices.
71
73
 
72
74
  ### Streaming (the headline)
73
75
 
@@ -106,8 +108,9 @@ client.update_session(session_id, permissions: permission_rules)
106
108
 
107
109
  OpenCode appends PATCHed permission rules and evaluates the last matching
108
110
  rule. Hosts should send a complete ordered policy and fingerprint it so the
109
- same policy is not appended on every turn. This endpoint requires OpenCode
110
- 1.16.1 or newer; the rest of the client remains compatible with 1.15.
111
+ same policy is not appended on every turn. This endpoint first appeared in
112
+ OpenCode 1.16.1; that version floor describes endpoint availability, not
113
+ compatibility with every later server.
111
114
 
112
115
  ### Lower-level event firehose
113
116
 
@@ -199,9 +202,29 @@ Want every OpenCode endpoint auto-generated from the OpenAPI spec? Use [`opencod
199
202
  ## Compatibility
200
203
 
201
204
  - Ruby ≥ 3.2
202
- - OpenCode server ≥ 1.15
203
205
  - Runtime dependency: `activesupport (>= 6.1)` — *not* Rails. ActiveSupport is a standalone helpers gem (`blank?`, `present?`, `presence`, `truncate`, etc.).
204
206
 
207
+ OpenCode server compatibility is evidence-based, not an open-ended SemVer
208
+ promise. OpenCode's HTTP, SSE, and runtime behavior can change independently
209
+ of a numeric version floor, so this gem does not infer compatibility from a
210
+ constraint such as `>= 1.15`.
211
+
212
+ Use the [OpenCode compatibility corpus](https://github.com/ajaynomics/opencode-compat)
213
+ as the source of current evidence. Its
214
+ [image matrix](https://github.com/ajaynomics/opencode-compat/blob/main/manifests/image-matrix.json)
215
+ records the exact gem commit and immutable OpenCode OCI digest exercised by
216
+ the `ruby-rest-sse` profile. Its
217
+ [runtime tuples](https://github.com/ajaynomics/opencode-compat/blob/main/manifests/runtime-tuples.json)
218
+ add the exact consumer commit and canary evidence needed for promotion and
219
+ rollback. A version label or image tag is provenance only, never the execution
220
+ coordinate.
221
+
222
+ A combination absent from passing evidence is **unverified**, not necessarily
223
+ incompatible. Run the corpus against the exact gem, image digest, and consumer
224
+ commit before adopting or promoting it. See the
225
+ [certification policy](https://github.com/ajaynomics/opencode-compat/blob/main/docs/certification.md)
226
+ for the full process.
227
+
205
228
  ## Development
206
229
 
207
230
  ```sh
@@ -213,10 +236,13 @@ The smoke suite covers Client end-to-end against WebMock-stubbed OpenCode
213
236
  endpoints, including subscription-before-prompt ordering and
214
237
  reconnect-without-repost.
215
238
 
216
- Releases use RubyGems trusted publishing. After the repository's
217
- `release.yml` workflow is registered as a trusted publisher with the `release`
218
- environment, pushing a `v*` tag builds, attests, and publishes the gem without
219
- a long-lived RubyGems API key.
239
+ The repository contains a tag-triggered `release.yml` workflow intended for
240
+ RubyGems trusted publishing, but its RubyGems trusted-publisher registration is
241
+ not configured as of `0.0.1.alpha7`; that release was published manually. A
242
+ `v*` tag push therefore does not currently guarantee publication. Before a
243
+ future release, verify the RubyGems registry result explicitly. Once the
244
+ workflow is registered as a trusted publisher for the `release` environment,
245
+ it can build, attest, and publish without a long-lived RubyGems API key.
220
246
 
221
247
  ## License
222
248
 
@@ -255,6 +255,10 @@ module Opencode
255
255
  end
256
256
 
257
257
  MAX_SSE_BUFFER = 1_048_576 # 1 MB — safety valve against pathological server responses
258
+ # Keep CRLF atomic so it cannot backtrack into CR + LF and look like a
259
+ # blank line. SSE also permits bare CR and LF line endings.
260
+ SSE_EVENT_BOUNDARY = /(?>\r\n|[\r\n]){2}/
261
+ UTF8_BOM = "\xEF\xBB\xBF".b.freeze
258
262
  SSE_RECONNECT_DELAY = 0.1
259
263
  TRANSIENT_SSE_ERRORS = [
260
264
  EOFError,
@@ -360,6 +364,7 @@ module Opencode
360
364
  subscription_ready = on_subscribed.nil?
361
365
  begin
362
366
  buffer = String.new
367
+ first_sse_event = true
363
368
 
364
369
  http.request(request) do |response|
365
370
  unless response.is_a?(Net::HTTPSuccess)
@@ -386,9 +391,14 @@ module Opencode
386
391
  raise ServerError, "SSE buffer exceeded #{MAX_SSE_BUFFER} bytes"
387
392
  end
388
393
 
389
- while (idx = buffer.index("\n\n"))
390
- raw_event = buffer.slice!(0, idx + 2)
391
- event = parse_sse_event(raw_event, session_id)
394
+ while (boundary = buffer.match(SSE_EVENT_BOUNDARY))
395
+ raw_event = buffer.slice!(0, boundary.end(0))
396
+ event = parse_sse_event(
397
+ raw_event,
398
+ session_id,
399
+ allow_bom: first_sse_event
400
+ )
401
+ first_sse_event = false
392
402
  next unless event
393
403
 
394
404
  unless subscription_ready
@@ -639,11 +649,22 @@ module Opencode
639
649
  end
640
650
  end
641
651
 
642
- def parse_sse_event(raw, session_id)
643
- data_line = raw.lines.find { |l| l.start_with?("data: ") }
644
- return nil unless data_line
652
+ def parse_sse_event(raw, session_id, allow_bom: false)
653
+ if allow_bom && raw.b.start_with?(UTF8_BOM)
654
+ raw = raw.byteslice(UTF8_BOM.bytesize..)
655
+ end
656
+
657
+ data = raw.split(/\r\n|\r|\n/, -1).filter_map do |line|
658
+ next if line.start_with?(":")
659
+
660
+ field, value = line.split(":", 2)
661
+ next unless field == "data"
662
+
663
+ (value || "").delete_prefix(" ")
664
+ end
665
+ return nil if data.empty?
645
666
 
646
- json = JSON.parse(data_line.sub("data: ", "").strip, symbolize_names: true)
667
+ json = JSON.parse(data.join("\n"), symbolize_names: true)
647
668
 
648
669
  event_session = json.dig(:properties, :sessionID) ||
649
670
  json.dig(:properties, :info, :sessionID) ||
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Opencode
4
- VERSION = "0.0.1.alpha7"
4
+ VERSION = "0.0.1.alpha8"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opencode-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.alpha7
4
+ version: 0.0.1.alpha8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ajay Krishnan