tidewave 0.4.0 → 0.4.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 728311a2ea0525028ccf9209d06bc1079f9258e35d534409f4ac867ff5212d32
4
- data.tar.gz: 11c1b092dc830897e59cb39f71de745b840acfd6f8845bf058c9010a06258e75
3
+ metadata.gz: 2ecc3b3a79123c50c7ec933b8cea5e2e4f61aff33671db1237c69a7536b31071
4
+ data.tar.gz: 14781db2f527923f2c5a52c4830c055659abd2e06d49526dd4630df0cd63d22a
5
5
  SHA512:
6
- metadata.gz: f9b49181b3f571b668de00287f0fec47088256ee335e31036385cedcb3b8c34274529d70a4f21d9c114279d9a1f5e52a56cab75b8465546863e0fd539fd1b390
7
- data.tar.gz: 1201a00a28892246592c158bc0e90cb5a6ce5d69a6a3533ef81bb8c853d2124d3544d029e8346613fa4d099010869f83cae49bcad82d890d1e935ee9f54903f4
6
+ metadata.gz: 39710ecba05ce8a3bf8686695c4602282fd6ee27356f4cc532cb78ea57a16403d2eb60059163b21ed5b3a3cc9225ae51a32a18df7eeee5b6e70197aae246ab26
7
+ data.tar.gz: e87dccaff2712bb7df136913ab409d9cc818f81444fb3892025541a274ba4ba4f17986bc425ba10c99e414668a7531a5773a8f5043c27b58b1af2d0c53a03538
data/README.md CHANGED
@@ -1,42 +1,47 @@
1
1
  # Tidewave
2
2
 
3
- Tidewave is the coding agent for full-stack web app development, deeply integrated with Rails, from the database to the UI. [See our website](https://tidewave.ai) for more information.
3
+ Tidewave is the coding agent for full-stack web app development. Integrate Claude Code, OpenAI Codex, and other agents with your web app and web framework at every layer, from UI to database. [See our website](https://tidewave.ai) for more information.
4
4
 
5
- This project can also be used as a standalone Model Context Protocol server for your editors.
5
+ This project can also be used as [a standalone Model Context Protocol server](https://hexdocs.pm/tidewave/mcp.html).
6
6
 
7
7
  ## Installation
8
8
 
9
- You can install Tidewave by adding the `tidewave` gem to the development group in your Gemfile:
9
+ You can install Tidewave by running:
10
+
11
+ ```shell
12
+ bundle add tidewave --group development
13
+ ```
14
+
15
+ or by manully adding the `tidewave` gem to the development group in your Gemfile:
10
16
 
11
17
  ```ruby
12
18
  gem "tidewave", group: :development
13
19
  ```
14
20
 
15
- Now access `/tidewave` route of your web application to enjoy Tidewave Web!
21
+ Now make sure [Tidewave is installed](https://hexdocs.pm/tidewave/installation.html) and you are ready to connect Tidewave to your app.
16
22
 
17
23
  ## Troubleshooting
18
24
 
19
- ### Localhost requirement
25
+ ### Using multiple hosts/subdomains
20
26
 
21
- Tidewave expects your web application to be running on `localhost`. If you are not running on localhost, you may need to set some additional configuration. In particular, you must configure Tidewave to allow `allow_remote_access` and [optionally configure your Rails hosts](https://guides.rubyonrails.org/configuring.html#actiondispatch-hostauthorization). For example, in your `config/environments/development.rb`:
27
+ If you are using multiple hosts/subdomains during development, you must use `*.localhost`, as such domains are considered secure by browsers. Additionally, add the following to `config/initializers/development.rb`:
22
28
 
23
29
  ```ruby
24
- config.hosts << "company.local"
25
- config.tidewave.allow_remote_access = true
30
+ config.session_store :cookie_store,
31
+ key: "__your_app_session",
32
+ same_site: :none,
33
+ secure: true,
34
+ assume_ssl: true
26
35
  ```
27
36
 
28
- If you want to use Docker for development, you either need to enable the configuration above or automatically redirect the relevant ports, as done by [devcontainers](https://code.visualstudio.com/docs/devcontainers/containers). See our [containers](https://hexdocs.pm/tidewave/containers.html) guide for more information.
37
+ And make sure you are using `rack-session` version `2.1.0` or later.
38
+
39
+ The above will allow your application to run embedded within Tidewave across multiple subdomains, as long as it is using a secure context (such as `admin.localhost`, `www.foobar.localhost`, etc).
29
40
 
30
41
  ### Content security policy
31
42
 
32
43
  If you have enabled Content-Security-Policy, Tidewave will automatically enable "unsafe-eval" under `script-src` in order for contextual browser testing to work correctly. It also disables the `frame-ancestors` directive.
33
44
 
34
- ### Web server requirements
35
-
36
- At the moment, Tidewave requires all requests to be processed by the same process. In case Tidewave cannot connect to your application, consider starting your Rails application as follows:
37
-
38
- RAILS_MAX_THREADS=1 WEB_CONCURRENCY=1 rails server
39
-
40
45
  ### Production Environment
41
46
 
42
47
  Tidewave is a powerful tool that can help you develop your web application faster and more efficiently. However, it is important to note that Tidewave is not meant to be used in a production environment.
@@ -48,12 +53,12 @@ Tidewave will raise an error if it is used in any environment where code reloadi
48
53
  You may configure `tidewave` using the following syntax:
49
54
 
50
55
  ```ruby
51
- config.tidewave.allow_remote_access = true
56
+ config.tidewave.team = { id: "my-company" }
52
57
  ```
53
58
 
54
59
  The following config is available:
55
60
 
56
- * `allow_remote_access` - Tidewave only allows requests from localhost by default, even if your server listens on other interfaces as well. If you trust your network and need to access Tidewave from a different machine, this configuration can be set to `true`
61
+ * `allow_remote_access` - Tidewave only allows requests from localhost by default, even if your server listens on other interfaces. If you trust your network and need to access Tidewave from a different machine, this configuration can be set to `true`
57
62
 
58
63
  * `logger_middleware` - The logger middleware Tidewave should wrap to silence its own logs
59
64
 
@@ -61,6 +66,26 @@ The following config is available:
61
66
 
62
67
  * `team` - set your Tidewave Team configuration, such as `config.tidewave.team = { id: "my-company" }`
63
68
 
69
+ ## Available tools
70
+
71
+ - `execute_sql_query` - executes a SQL query within your application
72
+ database, useful for the agent to verify the result of an action
73
+
74
+ - `get_docs` - get the documentation for a given module/class/method.
75
+ It consults the exact versions used by the project, ensuring you always
76
+ get correct information
77
+
78
+ - `get_logs` - reads logs written by the server
79
+
80
+ - `get_models` - lists all modules in the application and their location
81
+ for quick discovery
82
+
83
+ - `get_source_location` - get the source location for a given module/class/method,
84
+ so an agent can directly read the source skipping search
85
+
86
+ - `project_eval` - evaluates code within the Rails application itself, giving the agent
87
+ access to your runtime, dependencies, and in-memory data
88
+
64
89
  ## Acknowledgements
65
90
 
66
91
  A thank you to Yorick Jacquin, for creating [FastMCP](https://github.com/yjacquin/fast_mcp) and implementing the initial version of this project.
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "open3"
4
3
  require "ipaddr"
5
4
  require "fast_mcp"
6
5
  require "rack/request"
@@ -13,7 +12,6 @@ require_relative "streamable_http_transport"
13
12
  class Tidewave::Middleware
14
13
  TIDEWAVE_ROUTE = "tidewave".freeze
15
14
  MCP_ROUTE = "mcp".freeze
16
- SHELL_ROUTE = "shell".freeze
17
15
  CONFIG_ROUTE = "config".freeze
18
16
 
19
17
  INVALID_IP = <<~TEXT.freeze
@@ -64,8 +62,6 @@ class Tidewave::Middleware
64
62
  return home(request)
65
63
  when [ "GET", [ TIDEWAVE_ROUTE, CONFIG_ROUTE ] ]
66
64
  return config_endpoint(request)
67
- when [ "POST", [ TIDEWAVE_ROUTE, SHELL_ROUTE ] ]
68
- return shell(request)
69
65
  end
70
66
  end
71
67
 
@@ -88,7 +84,6 @@ class Tidewave::Middleware
88
84
  <head>
89
85
  <meta charset="UTF-8" />
90
86
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
91
- <meta name="tidewave:config" content="#{ERB::Util.html_escape(JSON.generate(config))}" />
92
87
  <script type="module" src="#{@client_url}/tc/tc.js"></script>
93
88
  </head>
94
89
  <body></body>
@@ -116,66 +111,6 @@ class Tidewave::Middleware
116
111
  [ 403, { "Content-Type" => "text/plain" }, [ message ] ]
117
112
  end
118
113
 
119
- def shell(request)
120
- body = request.body.read
121
- return [ 400, { "Content-Type" => "text/plain" }, [ "Command body is required" ] ] if body.blank?
122
-
123
- begin
124
- parsed_body = JSON.parse(body)
125
- cmd = parsed_body["command"]
126
- return [ 400, { "Content-Type" => "text/plain" }, [ "Command field is required" ] ] if cmd.blank?
127
- rescue JSON::ParserError
128
- return [ 400, { "Content-Type" => "text/plain" }, [ "Invalid JSON in request body" ] ]
129
- end
130
-
131
- response = Rack::Response.new
132
- response.status = 200
133
- response.headers["Content-Type"] = "text/plain"
134
-
135
- response.finish do |res|
136
- begin
137
- Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thr|
138
- stdin.close
139
-
140
- # Merge stdout and stderr streams
141
- ios = [ stdout, stderr ]
142
-
143
- until ios.empty?
144
- ready = IO.select(ios, nil, nil, 0.1)
145
- next unless ready
146
-
147
- ready[0].each do |io|
148
- begin
149
- data = io.read_nonblock(4096)
150
- if data
151
- # Write binary chunk: type (0 for data) + 4-byte length + data
152
- chunk = [ 0, data.bytesize ].pack("CN") + data
153
- res.write(chunk)
154
- end
155
- rescue IO::WaitReadable
156
- # No data available right now
157
- rescue EOFError
158
- # Stream ended
159
- ios.delete(io)
160
- end
161
- end
162
- end
163
-
164
- # Wait for process to complete and get exit status
165
- exit_status = wait_thr.value.exitstatus
166
- status_json = JSON.generate({ status: exit_status })
167
- # Write binary chunk: type (1 for status) + 4-byte length + JSON data
168
- chunk = [ 1, status_json.bytesize ].pack("CN") + status_json
169
- res.write(chunk)
170
- end
171
- rescue => e
172
- error_json = JSON.generate({ status: 213 })
173
- chunk = [ 1, error_json.bytesize ].pack("CN") + error_json
174
- res.write(chunk)
175
- end
176
- end
177
- end
178
-
179
114
  def valid_client_ip?(request)
180
115
  return true if @allow_remote_access
181
116
 
@@ -10,6 +10,27 @@ require "tidewave/quiet_requests_middleware"
10
10
  gem_tools_path = File.expand_path("tools/**/*.rb", __dir__)
11
11
  Dir[gem_tools_path].each { |f| require f }
12
12
 
13
+ # Temporary monkey patching to address regression in FastMCP
14
+ if Dry::Schema::Macros::Hash.method_defined?(:original_call)
15
+ Dry::Schema::Macros::Hash.class_eval do
16
+ def call(*args, &block)
17
+ if block
18
+ # Use current context to track nested context if available
19
+ context = MetadataContext.current
20
+ if context
21
+ context.with_nested(name) do
22
+ original_call(*args, &block)
23
+ end
24
+ else
25
+ original_call(*args, &block)
26
+ end
27
+ else
28
+ original_call(*args)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
13
34
  module Tidewave
14
35
  class Railtie < Rails::Railtie
15
36
  config.tidewave = Tidewave::Configuration.new()
@@ -76,11 +76,15 @@ module Tidewave
76
76
 
77
77
  @logger.debug("Sending response: #{@captured_response.inspect}")
78
78
 
79
- [
80
- 200,
81
- { "Content-Type" => "application/json" },
82
- [ JSON.generate(@captured_response) ]
83
- ]
79
+ if @captured_response
80
+ [
81
+ 200,
82
+ { "Content-Type" => "application/json" },
83
+ [ JSON.generate(@captured_response) ]
84
+ ]
85
+ else
86
+ [ 202, {}, [] ]
87
+ end
84
88
  rescue JSON::ParserError => e
85
89
  @logger.error("Invalid JSON in request: #{e.message}")
86
90
  json_rpc_error_response(400, -32700, "Parse error", nil)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tidewave
4
- VERSION = "0.4.0"
4
+ VERSION = "0.4.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tidewave
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yorick Jacquin
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2025-10-17 00:00:00.000000000 Z
12
+ date: 2026-02-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails