From df01387124e25b6e892a7ee8eb6e00e94ad770a4 Mon Sep 17 00:00:00 2001 From: Ajay Krishnan Date: Wed, 20 May 2026 06:35:58 -0700 Subject: [PATCH] Code review actions: rename version file, drop Gemfile conditional, tighten gemspec, switch URLs to GitHub MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three tightly-coupled cleanups from the Tobi+Sandi review: 1. Rename lib/opencode/rails/version.rb -> lib/opencode/rails_version.rb (Sandi S1: file path was lying about its contents — the file defines Opencode::RAILS_VERSION, NOT Opencode::Rails::VERSION). Updated the require_relative in opencode-rails.gemspec and lib/opencode-rails.rb to match. Removed the now-empty lib/opencode/rails/ directory. 2. Drop the 'if File.exist?(...) gem opencode-ruby, path: ...' Gemfile conditional (Tobi T2 / Sandi S4: Bundler behavior must not depend on filesystem state). The dev-time sibling-repo override is now documented in CONTRIBUTING.md as the standard 'bundle config local.opencode-ruby ' pattern, which is what Bundler ships for this use case. 3. Tighten opencode-ruby runtime dep from '~> 0.0.1.alpha1' to '= 0.0.1.alpha1' (Tobi T1: ~> during alpha is aspirational; pin exactly until the public API stabilizes). Same commit also switches all forward-looking URLs (gemspec homepage, metadata, README link to opencode-ruby) from Gitea to GitHub since the gems will eventually publish there. Functional 'git:' URL in ajent-rails' Gemfile stays on Gitea — that's where the gems actually are right now; ajent-rails Gemfile flips to GitHub when the user does the actual remote setup. Test assertion in loading_test was tightened to match either an installed-gem path ('gems/opencode-X-VERSION/') or a sibling-repo checkout ('/opencode-X/'), via a small GEM_PATH_PATTERN helper. 15 tests, 50 assertions, 0 failures. --- CONTRIBUTING.md | 71 +++++++++++++++++++ Gemfile | 8 --- README.md | 2 +- lib/opencode-rails.rb | 2 +- .../{rails/version.rb => rails_version.rb} | 0 opencode-rails.gemspec | 15 ++-- test/opencode/loading_test.rb | 12 +++- 7 files changed, 92 insertions(+), 18 deletions(-) create mode 100644 CONTRIBUTING.md rename lib/opencode/{rails/version.rb => rails_version.rb} (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..d6c4315 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,71 @@ +# Contributing to opencode-rails + +## Running the test suite + +```bash +bundle install +bundle exec rake test +``` + +The smoke tests live in `test/opencode/`. They prove that: + +- Every gem-provided constant resolves +- The opencode-ruby umbrella loads transitively +- Source locations point at the right gem +- The version constant is not under an `Opencode::Rails` module + (that would shadow `::Rails` in host apps; see comment in + `lib/opencode/rails_version.rb`) +- Public API contracts on the AR-coupled classes hold (Session, Turn, + MessageArtifacts) — verified via `Method#parameters`, not behavior +- Value objects (Artifact, SandboxFile, Transform, Impostor) round-trip + through their public interfaces + +Behavioral tests for AR + ActiveStorage paths live in the host app +that originally produced this code (`ajaynomics/ajent-rails`'s +`test/lib/opencode/rails/`). Same pattern as opencode-ruby. + +## Working on opencode-rails together with opencode-ruby + +opencode-rails depends on opencode-ruby. During development of either +gem you frequently need changes in opencode-ruby to be picked up by +opencode-rails without going through a release cycle. + +**Use Bundler's `local` config — not Gemfile conditionals.** Bundler +behavior must never depend on filesystem state inside the Gemfile. + +```bash +# Once per dev machine. Replace the path with wherever you have +# opencode-ruby checked out. +bundle config local.opencode-ruby /path/to/opencode-ruby + +# Then bundle install/update against the local copy: +bundle install +``` + +To switch back to the released version: + +```bash +bundle config --delete local.opencode-ruby +bundle install +``` + +See [Bundler's documentation on local git overrides](https://bundler.io/v2.5/git.html#local). + +## Releasing + +This gem is in alpha. Versions ship as `0.0.x.alphaN` until the public +API stabilizes. + +Coordinated releases with opencode-ruby: + +1. In opencode-ruby: bump `Opencode::VERSION`, tag, push. +2. In opencode-rails: bump `Opencode::RAILS_VERSION`, update the + `add_runtime_dependency "opencode-ruby", "= X.Y.Z"` line in the + gemspec to match the new opencode-ruby version (alpha discipline: + pin exactly, not pessimistically). Tag, push. +3. In any consumer (e.g., ajent-rails): bump both `tag:` lines in the + Gemfile to the new versions; `bundle update opencode-ruby opencode-rails`. + +## Reporting issues + +File at . diff --git a/Gemfile b/Gemfile index 0560e3a..b4e2a20 100644 --- a/Gemfile +++ b/Gemfile @@ -1,11 +1,3 @@ source "https://rubygems.org" -# opencode-ruby is the underlying wire client. During alpha both gems -# evolve in lockstep; the gemspec pins a release version, but for local -# dev we pull from the sibling working copy so changes in opencode-ruby -# are picked up without a release cycle. -if File.exist?(File.expand_path("../opencode-ruby", __dir__)) - gem "opencode-ruby", path: File.expand_path("../opencode-ruby", __dir__) -end - gemspec diff --git a/README.md b/README.md index bfae076..2251910 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # opencode-rails -Production-grade [OpenCode](https://opencode.ai) integration for Rails apps. Layers an ActiveRecord-aware session lifecycle, a turn orchestrator, an artifact pipeline, and a sandbox model on top of the wire-level client in [`opencode-ruby`](https://gitea.krishnan.ca/ajaynomics/opencode-ruby). +Production-grade [OpenCode](https://opencode.ai) integration for Rails apps. Layers an ActiveRecord-aware session lifecycle, a turn orchestrator, an artifact pipeline, and a sandbox model on top of the wire-level client in [`opencode-ruby`](https://github.com/ajaynomics/opencode-ruby). > **Alpha software.** API will change before 1.0. Pin to a specific version. diff --git a/lib/opencode-rails.rb b/lib/opencode-rails.rb index 69f5c26..9b7b93a 100644 --- a/lib/opencode-rails.rb +++ b/lib/opencode-rails.rb @@ -17,7 +17,7 @@ require "active_support/core_ext/string/inflections" # demodulize, underscore, c require "active_support/core_ext/string/filters" # squish, truncate require "active_support/core_ext/numeric/time" # 2.seconds, 5.minutes, etc. -require_relative "opencode/rails/version" +require_relative "opencode/rails_version" require_relative "opencode/error_reporter" # Tier 4 leaves (no deps on other rails-gem files) diff --git a/lib/opencode/rails/version.rb b/lib/opencode/rails_version.rb similarity index 100% rename from lib/opencode/rails/version.rb rename to lib/opencode/rails_version.rb diff --git a/opencode-rails.gemspec b/opencode-rails.gemspec index 85acb43..5f9a027 100644 --- a/opencode-rails.gemspec +++ b/opencode-rails.gemspec @@ -1,6 +1,6 @@ # frozen_string_literal: true -require_relative "lib/opencode/rails/version" +require_relative "lib/opencode/rails_version" Gem::Specification.new do |spec| spec.name = "opencode-rails" @@ -19,22 +19,25 @@ Gem::Specification.new do |spec| production-grade OpenCode streaming without rolling your own boilerplate. DESC - spec.homepage = "https://gitea.krishnan.ca/ajaynomics/opencode-rails" + spec.homepage = "https://github.com/ajaynomics/opencode-rails" spec.license = "MIT" spec.required_ruby_version = ">= 3.2.0" + spec.metadata["homepage_uri"] = spec.homepage spec.metadata["source_code_uri"] = spec.homepage - spec.metadata["changelog_uri"] = "#{spec.homepage}/src/branch/main/CHANGELOG.md" + spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md" spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues" spec.files = Dir.glob("lib/**/*.rb") + + Dir.glob("examples/**/*.rb") + %w[README.md LICENSE CHANGELOG.md opencode-rails.gemspec] spec.require_paths = ["lib"] # The opencode-ruby gem provides the wire-level Client + Reply primitives - # this gem builds on. Versions are kept in lockstep during the alpha - # phase; will relax to a looser pessimistic pin once both gems stabilize. - spec.add_runtime_dependency "opencode-ruby", "~> 0.0.1.alpha1" + # this gem builds on. During alpha both gems evolve in lockstep — we pin + # exactly (= not ~>) so that consumers always pick the version this gem + # was tested against. Bump to alpha2 when the paired release ships. + spec.add_runtime_dependency "opencode-ruby", "= 0.0.1.alpha1" # Rails sub-libraries used at runtime. Depending on these individually # (instead of the `rails` umbrella) avoids forcing host apps to load diff --git a/test/opencode/loading_test.rb b/test/opencode/loading_test.rb index 859d787..b048b6c 100644 --- a/test/opencode/loading_test.rb +++ b/test/opencode/loading_test.rb @@ -36,16 +36,24 @@ class Opencode::LoadingTest < Minitest::Test end end + # We check via path match on both directory ("/opencode-rails/") and + # installed-gem name ("/opencode-rails-VERSION/") so the assertion is + # robust to either a sibling-repo dev setup or a bundle-resolved gem + # install. + GEM_PATH_PATTERN = ->(name) { %r{/#{Regexp.escape(name)}[-/]} } + def test_session_constant_points_at_this_gem location = Opencode::Session.instance_method(:initialize).source_location.first - assert_match %r{/opencode-rails/}, location, + assert_match GEM_PATH_PATTERN.call("opencode-rails"), location, "Expected Opencode::Session to be loaded from opencode-rails, got: #{location}" end def test_client_constant_points_at_opencode_ruby location = Opencode::Client.instance_method(:initialize).source_location.first - assert_match %r{/opencode-ruby/}, location, + assert_match GEM_PATH_PATTERN.call("opencode-ruby"), location, "Expected Opencode::Client to come from opencode-ruby, got: #{location}" + refute_match GEM_PATH_PATTERN.call("opencode-rails"), location, + "Opencode::Client must NOT come from opencode-rails (it's an opencode-ruby class)" end def test_version_constant