coatepec 0.4.0 → 0.5.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 503cdd08a244ae010df42c9698c214d4a1e916969bae0f96ddaa62dfed2c2157
4
- data.tar.gz: 54672230e5e1905f78f53d5614be4dccbcf0b5a9392fd3d0caae22dcf7d8c719
3
+ metadata.gz: 7cbcec579a7904ef50c8d8227036bbb0dd45f05bd664ffa2fceb2d210f5171be
4
+ data.tar.gz: 672092f99f2bfab2de7ad832572e6f16b5aeea8613860f0456fc81f7abaf25f4
5
5
  SHA512:
6
- metadata.gz: f33a3b662004ab4aaba6d80ade9176952c90730ebe44a009f4f3443db5888c56b7fd8094b87c17b7be8a29519f7f067c2c6efcdb796249a4da3bc81945b236af
7
- data.tar.gz: 8bfe0dccc1861c8b8923a8e049898ad8ead99da9febc5b85274914dad61ac52f06c3d5726e14d05b097e425e9a6c98eba1e3bca3bc98a51b6ea1227fb4b96bf7
6
+ metadata.gz: f065ef0f83fbf5796d8e333326d9cf852a7322de12a12f77ece713df6cf00d29f167ea3ca2001830cb70e1e770a4533e3b111956390da1d0968c682cdeb8335a
7
+ data.tar.gz: 62d2d70afe6f5554c4e40fd83572384161f1819b228e65baa5c3a9c048716632e47c126356810e0c5aeb1e2ca1e9a79ed30fe0d10e97e773d6f1b6527a373d38
data/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.5.0
4
+
5
+ - **Breaking:** `mcp` is no longer a runtime dependency of the `coatepec`
6
+ gem -- it's a development dependency, since Coatepec is meant to be
7
+ installed once outside any Rails app's own bundle and pointed at the app
8
+ via `--root`, not added to the app's `Gemfile` (`Worker::Client` resolves
9
+ the worker's `RUBYLIB` from Coatepec's own installation regardless).
10
+ Anyone whose MCP config currently launches Coatepec with `bundle exec
11
+ coatepec` from inside a target app's bundle will hit a `LoadError` on
12
+ upgrade once that bundle no longer pulls in `mcp` transitively.
13
+
14
+ **Migration:** `gem install mcp` alongside `coatepec`, and change your MCP
15
+ client config to invoke `coatepec` directly rather than `bundle exec
16
+ coatepec` (drop the `coatepec` line from the target app's `Gemfile` too,
17
+ if present -- see the README Quickstart for the corrected install story).
18
+
19
+ ## 0.4.1
20
+
21
+ - Fix `exe/coatepec-worker` booting against a target app whose locally
22
+ installed default-gem versions (e.g. `json`) differ from what its
23
+ `Gemfile.lock` pins: `require "bundler/setup"` now runs before
24
+ `require "coatepec"` itself, so Bundler can pin default gems before
25
+ Ruby auto-activates a newer locally installed version and locks it in
26
+ for the rest of the process. Previously this broke every coatepec call
27
+ against such an app with `already activated X, but your Gemfile
28
+ requires Y`.
29
+
3
30
  ## 0.4.0
4
31
 
5
32
  - Add `enums` to `rails_model`'s output, sourced from ActiveRecord's own
data/README.md CHANGED
@@ -6,26 +6,31 @@ console.
6
6
 
7
7
  ## Quickstart
8
8
 
9
- ```ruby
10
- # Gemfile
11
- group :development, :test do
12
- gem "coatepec", require: false
13
- end
14
- ```
9
+ Coatepec is installed once, outside of any Rails app's own bundle, and
10
+ points at the app via `--root`:
15
11
 
16
12
  ```bash
17
- bundle install
18
- bundle exec coatepec --version
13
+ gem install coatepec mcp
14
+ coatepec --version
19
15
  ```
20
16
 
21
- Configure your MCP client to run `bundle exec coatepec --root /absolute/path/to/app`
22
- from the Rails application's own bundle.
17
+ Do not add `coatepec` to the target app's `Gemfile`. `Worker::Client#spawn_worker`
18
+ resolves both the worker executable and its `RUBYLIB` from Coatepec's own
19
+ installation, not from the app's bundle -- so the worker gets Coatepec's
20
+ `lib` regardless of what the app's Gemfile says. Adding it there is not just
21
+ redundant, it's a version-skew hazard: Bundler would activate whatever
22
+ version is in the app's lockfile while Coatepec itself keeps running the
23
+ version on `RUBYLIB`, and a drift between the two surfaces as a confusing
24
+ "already activated" failure. The only thing Coatepec needs from the target
25
+ app is `railties`, which is definitionally present in any Rails app you'd
26
+ point it at. Host app footprint is zero: no Gemfile line, no lockfile
27
+ change, no dependency resolution.
23
28
 
24
29
  With the [Claude Code CLI](https://docs.claude.com/en/docs/claude-code),
25
30
  from the Rails app's own root:
26
31
 
27
32
  ```bash
28
- claude mcp add coatepec --scope project -- bundle exec coatepec --root .
33
+ claude mcp add coatepec --scope project -- coatepec --root .
29
34
  ```
30
35
 
31
36
  That writes a project-scoped `.mcp.json` you can commit so the whole team
@@ -36,8 +41,8 @@ same thing looks like:
36
41
  {
37
42
  "mcpServers": {
38
43
  "coatepec": {
39
- "command": "bundle",
40
- "args": ["exec", "coatepec", "--root", "."]
44
+ "command": "coatepec",
45
+ "args": ["--root", "."]
41
46
  }
42
47
  }
43
48
  }
@@ -93,6 +98,29 @@ includes an `execution_mode` field (`fork`, `spawn_fallback`, or
93
98
  call; `spawn_after_crash` results also carry the crashed fork's own stderr
94
99
  under `crashed_fork_stderr` so the crash can be diagnosed.
95
100
 
101
+ `macos_fork: true` also effectively requires
102
+ `OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES` in Coatepec's own environment.
103
+ Without it, a forked child that touches an Objective-C-initialized class
104
+ aborts -- Coatepec retries via spawn, so it degrades silently to the slow
105
+ path (no crash, no error surfaced) rather than failing loudly, and you
106
+ simply never get the speedup. Set it on the MCP server process itself:
107
+
108
+ ```json
109
+ {
110
+ "mcpServers": {
111
+ "coatepec": {
112
+ "command": "coatepec",
113
+ "args": ["--root", "."],
114
+ "env": { "OBJC_DISABLE_INITIALIZE_FORK_SAFETY": "YES" }
115
+ }
116
+ }
117
+ }
118
+ ```
119
+
120
+ Be aware this flag disables a real safety check in Apple's Objective-C
121
+ runtime; it's a reasonable trade for a local dev/test sidecar, but it's not
122
+ a no-op.
123
+
96
124
  ## Tools
97
125
 
98
126
  | Tool | Input | Notes |
@@ -115,6 +143,16 @@ worker). For most apps this is invisible, but if you ever see behavior differ
115
143
  between Coatepec and your own `bundle exec rspec`, this is the first thing to
116
144
  suspect.
117
145
 
146
+ ### Restarts
147
+
148
+ If any tool call fails with `sidecar_restart_required`, the target app's
149
+ `Gemfile`/`Gemfile.lock` changed since Coatepec's own parent process (the
150
+ "sidecar") started -- not just the warm test worker, which Coatepec restarts
151
+ on its own. This is expected any time you switch branches, pull, or rebase
152
+ across a commit that touches the Gemfile, since the sidecar is managed by
153
+ your MCP client rather than by Coatepec itself: restart your MCP client (or
154
+ however it manages the Coatepec process) to pick up the change.
155
+
118
156
  ## Security boundary
119
157
 
120
158
  No eval, console, SQL/record access, shell, Rake, or file-write tool. Spec
data/exe/coatepec-worker CHANGED
@@ -1,6 +1,20 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
+ # Must run before any other require, including "coatepec" itself. Ruby
5
+ # auto-activates the newest installed version of a default gem (json,
6
+ # among others) the moment anything requires it, and a gem version can't
7
+ # be changed once activated -- so if that happens before Bundler pins
8
+ # versions to what the target app's Gemfile.lock actually specifies,
9
+ # Bundler.setup then fails with "already activated X, but your Gemfile
10
+ # requires Y" for any default gem that happens to have a newer version
11
+ # installed locally than what's locked. require "coatepec" below pulls in
12
+ # "json" (via protocol.rb) as its very first transitive require, so it's
13
+ # exactly the kind of require this has to run ahead of.
14
+ # Worker::Client#spawn_worker already sets BUNDLE_GEMFILE to the target
15
+ # app's Gemfile before this process starts.
16
+ require "bundler/setup"
17
+
4
18
  require "coatepec"
5
19
 
6
20
  # Preserve a real handle to the OS stdout fd for the private NDJSON
data/lib/coatepec/mcp.rb CHANGED
@@ -1,6 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "mcp"
3
+ begin
4
+ require "mcp"
5
+ rescue LoadError
6
+ raise LoadError, "The \"mcp\" gem is required to run Coatepec but is not installed. " \
7
+ "Install it alongside Coatepec: `gem install coatepec mcp`."
8
+ end
9
+
4
10
  require "coatepec"
5
11
  require_relative "mcp/response"
6
12
  require_relative "mcp/tools"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Coatepec
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  end
@@ -68,7 +68,10 @@ module Coatepec
68
68
  reason = @change_detector.restart_reason(@snapshot)
69
69
  case reason
70
70
  when :sidecar_restart_required
71
- raise Coatepec::Error.new(:sidecar_restart_required, "Gemfile changed; restart Coatepec")
71
+ raise Coatepec::Error.new(
72
+ :sidecar_restart_required,
73
+ "Gemfile changed; restart your MCP client to restart Coatepec and pick up the change"
74
+ )
72
75
  when :worker_restart_required
73
76
  restart_worker!
74
77
  end
metadata CHANGED
@@ -1,28 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coatepec
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Enrique Mogollan
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-08-02 00:00:00.000000000 Z
10
+ date: 2026-08-05 00:00:00.000000000 Z
11
11
  dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: mcp
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - "~>"
17
- - !ruby/object:Gem::Version
18
- version: '1.0'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - "~>"
24
- - !ruby/object:Gem::Version
25
- version: '1.0'
26
12
  - !ruby/object:Gem::Dependency
27
13
  name: railties
28
14
  requirement: !ruby/object:Gem::Requirement
@@ -43,6 +29,20 @@ dependencies:
43
29
  - - "<"
44
30
  - !ruby/object:Gem::Version
45
31
  version: '8.2'
32
+ - !ruby/object:Gem::Dependency
33
+ name: mcp
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - "~>"
37
+ - !ruby/object:Gem::Version
38
+ version: '1.0'
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - "~>"
44
+ - !ruby/object:Gem::Version
45
+ version: '1.0'
46
46
  description: Coatepec is a local stdio MCP sidecar that keeps an isolated Rails test
47
47
  worker warm so coding agents can run targeted RSpec examples quickly, without exposing
48
48
  a general Rails console.