woods 1.1.0 → 1.3.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.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +186 -0
  3. data/README.md +20 -8
  4. data/exe/woods-console +51 -6
  5. data/exe/woods-console-mcp +24 -4
  6. data/exe/woods-mcp +30 -7
  7. data/exe/woods-mcp-http +47 -6
  8. data/lib/generators/woods/install_generator.rb +13 -4
  9. data/lib/generators/woods/templates/woods.rb.tt +155 -0
  10. data/lib/tasks/woods.rake +69 -50
  11. data/lib/woods/builder.rb +174 -9
  12. data/lib/woods/cache/cache_middleware.rb +360 -31
  13. data/lib/woods/chunking/semantic_chunker.rb +334 -7
  14. data/lib/woods/console/adapters/job_adapter.rb +10 -4
  15. data/lib/woods/console/audit_logger.rb +76 -4
  16. data/lib/woods/console/bridge.rb +48 -15
  17. data/lib/woods/console/bridge_protocol.rb +44 -0
  18. data/lib/woods/console/confirmation.rb +3 -4
  19. data/lib/woods/console/console_response_renderer.rb +56 -18
  20. data/lib/woods/console/credential_index.rb +201 -0
  21. data/lib/woods/console/credential_scanner.rb +302 -0
  22. data/lib/woods/console/dispatch_pipeline.rb +138 -0
  23. data/lib/woods/console/embedded_executor.rb +682 -35
  24. data/lib/woods/console/eval_guard.rb +319 -0
  25. data/lib/woods/console/model_validator.rb +1 -3
  26. data/lib/woods/console/rack_middleware.rb +185 -29
  27. data/lib/woods/console/redactor.rb +161 -0
  28. data/lib/woods/console/response_context.rb +127 -0
  29. data/lib/woods/console/safe_context.rb +220 -23
  30. data/lib/woods/console/scope_predicate_parser.rb +131 -0
  31. data/lib/woods/console/server.rb +417 -486
  32. data/lib/woods/console/sql_noise_stripper.rb +87 -0
  33. data/lib/woods/console/sql_table_scanner.rb +213 -0
  34. data/lib/woods/console/sql_validator.rb +81 -31
  35. data/lib/woods/console/table_gate.rb +93 -0
  36. data/lib/woods/console/tool_specs.rb +552 -0
  37. data/lib/woods/console/tools/tier1.rb +3 -3
  38. data/lib/woods/console/tools/tier4.rb +7 -1
  39. data/lib/woods/dependency_graph.rb +66 -7
  40. data/lib/woods/embedding/indexer.rb +190 -6
  41. data/lib/woods/embedding/openai.rb +40 -4
  42. data/lib/woods/embedding/provider.rb +104 -8
  43. data/lib/woods/embedding/text_preparer.rb +23 -3
  44. data/lib/woods/embedding/token_counter.rb +133 -0
  45. data/lib/woods/evaluation/baseline_runner.rb +20 -2
  46. data/lib/woods/evaluation/metrics.rb +4 -1
  47. data/lib/woods/extracted_unit.rb +1 -0
  48. data/lib/woods/extractor.rb +7 -1
  49. data/lib/woods/extractors/controller_extractor.rb +6 -0
  50. data/lib/woods/extractors/mailer_extractor.rb +16 -2
  51. data/lib/woods/extractors/model_extractor.rb +6 -1
  52. data/lib/woods/extractors/phlex_extractor.rb +13 -4
  53. data/lib/woods/extractors/rails_source_extractor.rb +2 -0
  54. data/lib/woods/extractors/route_helper_resolver.rb +130 -0
  55. data/lib/woods/extractors/shared_dependency_scanner.rb +130 -2
  56. data/lib/woods/extractors/view_component_extractor.rb +12 -1
  57. data/lib/woods/extractors/view_engines/base.rb +141 -0
  58. data/lib/woods/extractors/view_engines/erb.rb +145 -0
  59. data/lib/woods/extractors/view_template_extractor.rb +92 -133
  60. data/lib/woods/flow_assembler.rb +23 -15
  61. data/lib/woods/flow_precomputer.rb +21 -2
  62. data/lib/woods/graph_analyzer.rb +210 -0
  63. data/lib/woods/index_artifact.rb +173 -0
  64. data/lib/woods/mcp/bearer_auth.rb +45 -0
  65. data/lib/woods/mcp/bootstrap_state.rb +94 -0
  66. data/lib/woods/mcp/bootstrapper.rb +337 -16
  67. data/lib/woods/mcp/config_resolver.rb +288 -0
  68. data/lib/woods/mcp/errors.rb +134 -0
  69. data/lib/woods/mcp/index_reader.rb +265 -30
  70. data/lib/woods/mcp/origin_guard.rb +132 -0
  71. data/lib/woods/mcp/provider_probe.rb +166 -0
  72. data/lib/woods/mcp/renderers/claude_renderer.rb +6 -0
  73. data/lib/woods/mcp/renderers/markdown_renderer.rb +100 -3
  74. data/lib/woods/mcp/renderers/plain_renderer.rb +16 -2
  75. data/lib/woods/mcp/server.rb +771 -137
  76. data/lib/woods/model_name_cache.rb +78 -2
  77. data/lib/woods/notion/client.rb +25 -2
  78. data/lib/woods/notion/mappers/model_mapper.rb +36 -2
  79. data/lib/woods/railtie.rb +55 -15
  80. data/lib/woods/resilience/circuit_breaker.rb +9 -2
  81. data/lib/woods/resilience/retryable_provider.rb +40 -3
  82. data/lib/woods/resolved_config.rb +299 -0
  83. data/lib/woods/retrieval/context_assembler.rb +112 -5
  84. data/lib/woods/retrieval/query_classifier.rb +1 -1
  85. data/lib/woods/retrieval/ranker.rb +55 -6
  86. data/lib/woods/retrieval/search_executor.rb +42 -13
  87. data/lib/woods/retriever.rb +330 -24
  88. data/lib/woods/session_tracer/middleware.rb +35 -1
  89. data/lib/woods/storage/graph_store.rb +39 -0
  90. data/lib/woods/storage/inapplicable_backend.rb +14 -0
  91. data/lib/woods/storage/metadata_store.rb +129 -1
  92. data/lib/woods/storage/pgvector.rb +70 -8
  93. data/lib/woods/storage/qdrant.rb +196 -5
  94. data/lib/woods/storage/snapshotter/metadata.rb +172 -0
  95. data/lib/woods/storage/snapshotter/vector.rb +238 -0
  96. data/lib/woods/storage/snapshotter.rb +24 -0
  97. data/lib/woods/storage/vector_store.rb +184 -35
  98. data/lib/woods/tasks.rb +85 -0
  99. data/lib/woods/temporal/snapshot_store.rb +49 -1
  100. data/lib/woods/token_utils.rb +44 -5
  101. data/lib/woods/unblocked/client.rb +163 -0
  102. data/lib/woods/unblocked/document_builder.rb +326 -0
  103. data/lib/woods/unblocked/exporter.rb +201 -0
  104. data/lib/woods/unblocked/rate_limiter.rb +94 -0
  105. data/lib/woods/util/host_guard.rb +61 -0
  106. data/lib/woods/version.rb +1 -1
  107. data/lib/woods.rb +130 -6
  108. metadata +73 -4
data/lib/woods.rb CHANGED
@@ -31,19 +31,113 @@ module Woods
31
31
 
32
32
  CONFIG_MUTEX = Mutex.new
33
33
 
34
+ # Console MCP secure defaults — Layer 3 column-name redaction.
35
+ #
36
+ # Columns named here are replaced with `[REDACTED]` in every MCP tool
37
+ # response. This list targets credential columns that appear with the
38
+ # same names across Devise, Doorkeeper, Rodauth, has_secure_password,
39
+ # devise-two-factor, OAuth integrations, and hand-rolled auth code.
40
+ #
41
+ # Intentionally omitted because they cause over-redaction in apps that
42
+ # use them for non-secret purposes:
43
+ # - `key` — ActiveStorage blob keys, EAV key columns, translation keys
44
+ # - `name` — universal non-secret identifier
45
+ # - PII columns (`ssn`, `tax_id`, `dob`) — org-specific compliance concern
46
+ #
47
+ # Host apps extend this by reassigning `console_redacted_columns` to
48
+ # `Woods::DEFAULT_CONSOLE_REDACTED_COLUMNS + %w[extra_column]`, or
49
+ # override entirely to remove a default.
50
+ DEFAULT_CONSOLE_REDACTED_COLUMNS = %w[
51
+ password
52
+ password_digest
53
+ password_salt
54
+ encrypted_password
55
+ crypted_password
56
+ salt
57
+ otp_secret
58
+ encrypted_otp_secret
59
+ two_factor_secret
60
+ backup_codes
61
+ consumed_timestep
62
+ reset_password_token
63
+ confirmation_token
64
+ unlock_token
65
+ remember_token
66
+ invitation_token
67
+ access_token
68
+ refresh_token
69
+ auth_token
70
+ api_token
71
+ api_key
72
+ bearer_token
73
+ client_secret
74
+ webhook_secret
75
+ signing_secret
76
+ session_secret
77
+ private_key
78
+ encrypted_private_key
79
+ key_hash
80
+ token
81
+ secret
82
+ ].freeze
83
+
84
+ # Console MCP secure defaults — Layer 1 table-level blocking.
85
+ #
86
+ # Tables named here are rejected outright before any SQL reaches the
87
+ # database. This list targets authentication and credential storage
88
+ # tables that carry secrets or session state across all major auth
89
+ # stacks (Devise, Doorkeeper, Rodauth, has_secure_password, Sorcery,
90
+ # OmniAuth, and hand-rolled token systems).
91
+ #
92
+ # Intentionally omitted to avoid over-blocking benign apps:
93
+ # - `users` / `accounts` — many apps expose safe columns from these
94
+ # tables and operators should decide explicitly.
95
+ # - PII-heavy but auth-unrelated tables (`payments`, `addresses`) —
96
+ # org-specific compliance concern, not a universal default.
97
+ #
98
+ # To keep the defaults and add more tables:
99
+ # Woods.configure { |c| c.console_blocked_tables =
100
+ # Woods::DEFAULT_CONSOLE_BLOCKED_TABLES + %w[extra_table] }
101
+ #
102
+ # To replace the defaults entirely (including removing entries):
103
+ # Woods.configure { |c| c.console_blocked_tables = %w[only_this] }
104
+ #
105
+ # To disable Layer 1 (gate becomes inactive; other layers still apply):
106
+ # Woods.configure { |c| c.console_blocked_tables = [] }
107
+ DEFAULT_CONSOLE_BLOCKED_TABLES = %w[
108
+ sessions
109
+ api_keys
110
+ credentials
111
+ oauth_applications
112
+ oauth_access_tokens
113
+ oauth_refresh_tokens
114
+ identities
115
+ active_storage_blobs
116
+ ].freeze
117
+
34
118
  # ════════════════════════════════════════════════════════════════════════
35
119
  # Configuration
36
120
  # ════════════════════════════════════════════════════════════════════════
37
121
 
38
- class Configuration
122
+ class Configuration # rubocop:disable Metrics/ClassLength
39
123
  attr_accessor :embedding_model, :include_framework_sources, :gem_configs,
40
124
  :vector_store, :metadata_store, :graph_store, :embedding_provider, :log_level,
41
125
  :vector_store_options, :metadata_store_options, :embedding_options,
42
- :concurrent_extraction, :precompute_flows, :enable_snapshots,
43
- :session_tracer_enabled, :session_store, :session_id_proc, :session_exclude_paths,
44
- :console_mcp_enabled, :console_mcp_path, :console_redacted_columns,
126
+ :concurrent_extraction, :precompute_flows, :extract_navigation_edges, :enable_snapshots,
127
+ :session_tracer_enabled, :session_tracer_allow_production,
128
+ :session_store, :session_id_proc, :session_exclude_paths,
129
+ :console_mcp_enabled, :console_mcp_path, :console_mcp_token,
130
+ :console_mcp_allowed_origins,
131
+ :console_redacted_columns,
132
+ :console_redacted_key_values, :console_embedded_read_tools,
133
+ :console_blocked_tables, :console_disabled_scanner_patterns,
134
+ :console_credential_defense_enabled,
135
+ :console_credential_rotation_warning, :console_unsafe_eval_enabled,
136
+ :console_unsafe_eval_confirmation, :console_unsafe_eval_audit_log_path,
45
137
  :notion_api_token, :notion_database_ids,
46
- :cache_store, :cache_options
138
+ :unblocked_api_token, :unblocked_collection_id, :unblocked_repo_url,
139
+ :cache_store, :cache_options,
140
+ :dump_retention_count
47
141
  attr_reader :max_context_tokens, :similarity_threshold, :extractors, :pretty_json, :context_format,
48
142
  :cache_enabled
49
143
 
@@ -59,20 +153,50 @@ module Woods
59
153
  @pretty_json = true
60
154
  @concurrent_extraction = false
61
155
  @precompute_flows = false
156
+ @extract_navigation_edges = true
62
157
  @enable_snapshots = false
63
158
  @context_format = :markdown
64
159
  @session_tracer_enabled = false
160
+ @session_tracer_allow_production = false
65
161
  @session_store = nil
66
162
  @session_id_proc = nil
67
163
  @session_exclude_paths = []
68
164
  @console_mcp_enabled = false
69
165
  @console_mcp_path = '/mcp/console'
70
- @console_redacted_columns = []
166
+ # Accept token from config or env var. Nil by default — the railtie
167
+ # refuses to wire the middleware in production without a real token
168
+ # and only warns loudly in non-prod when unset.
169
+ @console_mcp_token = ENV.fetch('WOODS_CONSOLE_MCP_TOKEN', nil)
170
+ # Origins allowed to reach the embedded console MCP. Loopback only
171
+ # by default; override in host initializers for tunneled or internal
172
+ # dashboard access.
173
+ @console_mcp_allowed_origins = %w[
174
+ http://localhost
175
+ http://127.0.0.1
176
+ http://[::1]
177
+ ]
178
+ @console_redacted_columns = DEFAULT_CONSOLE_REDACTED_COLUMNS.dup
179
+ @console_redacted_key_values = []
180
+ @console_embedded_read_tools = false
181
+ @console_blocked_tables = DEFAULT_CONSOLE_BLOCKED_TABLES.dup
182
+ @console_disabled_scanner_patterns = []
183
+ @console_credential_defense_enabled = true
184
+ @console_credential_rotation_warning = true
185
+ @console_unsafe_eval_enabled = nil # nil = fall back to env WOODS_CONSOLE_UNSAFE_EVAL
186
+ # Required collaborators when the opt-in is on. Both default to nil;
187
+ # the server refuses to boot with the opt-in set unless the host has
188
+ # wired them (fail-closed — see Server.build_embedded).
189
+ @console_unsafe_eval_confirmation = nil
190
+ @console_unsafe_eval_audit_log_path = nil
71
191
  @notion_api_token = nil
72
192
  @notion_database_ids = {}
193
+ @unblocked_api_token = nil
194
+ @unblocked_collection_id = nil
195
+ @unblocked_repo_url = nil
73
196
  @cache_enabled = false
74
197
  @cache_store = nil # :redis, :solid_cache, :memory, or a CacheStore instance
75
198
  @cache_options = {} # { redis: client, cache: store, ttl: { embeddings: 86400, ... } }
199
+ @dump_retention_count = 3
76
200
  end
77
201
 
78
202
  # @return [Pathname, String] Output directory, defaulting to Rails.root/tmp/woods
metadata CHANGED
@@ -1,29 +1,63 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: woods
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leah Armstrong
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-03-15 00:00:00.000000000 Z
11
+ date: 2026-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mcp
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.9.2
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '1.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 0.9.2
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '1.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: msgpack
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '1.5'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '1.5'
47
+ - !ruby/object:Gem::Dependency
48
+ name: prism
15
49
  requirement: !ruby/object:Gem::Requirement
16
50
  requirements:
17
51
  - - "~>"
18
52
  - !ruby/object:Gem::Version
19
- version: '0.6'
53
+ version: '1.4'
20
54
  type: :runtime
21
55
  prerelease: false
22
56
  version_requirements: !ruby/object:Gem::Requirement
23
57
  requirements:
24
58
  - - "~>"
25
59
  - !ruby/object:Gem::Version
26
- version: '0.6'
60
+ version: '1.4'
27
61
  - !ruby/object:Gem::Dependency
28
62
  name: railties
29
63
  requirement: !ruby/object:Gem::Requirement
@@ -69,6 +103,7 @@ files:
69
103
  - lib/generators/woods/pgvector_generator.rb
70
104
  - lib/generators/woods/templates/add_pgvector_to_woods.rb.erb
71
105
  - lib/generators/woods/templates/create_woods_tables.rb.erb
106
+ - lib/generators/woods/templates/woods.rb.tt
72
107
  - lib/tasks/woods.rake
73
108
  - lib/tasks/woods_evaluation.rake
74
109
  - lib/woods.rb
@@ -91,15 +126,27 @@ files:
91
126
  - lib/woods/console/adapters/solid_queue_adapter.rb
92
127
  - lib/woods/console/audit_logger.rb
93
128
  - lib/woods/console/bridge.rb
129
+ - lib/woods/console/bridge_protocol.rb
94
130
  - lib/woods/console/confirmation.rb
95
131
  - lib/woods/console/connection_manager.rb
96
132
  - lib/woods/console/console_response_renderer.rb
133
+ - lib/woods/console/credential_index.rb
134
+ - lib/woods/console/credential_scanner.rb
135
+ - lib/woods/console/dispatch_pipeline.rb
97
136
  - lib/woods/console/embedded_executor.rb
137
+ - lib/woods/console/eval_guard.rb
98
138
  - lib/woods/console/model_validator.rb
99
139
  - lib/woods/console/rack_middleware.rb
140
+ - lib/woods/console/redactor.rb
141
+ - lib/woods/console/response_context.rb
100
142
  - lib/woods/console/safe_context.rb
143
+ - lib/woods/console/scope_predicate_parser.rb
101
144
  - lib/woods/console/server.rb
145
+ - lib/woods/console/sql_noise_stripper.rb
146
+ - lib/woods/console/sql_table_scanner.rb
102
147
  - lib/woods/console/sql_validator.rb
148
+ - lib/woods/console/table_gate.rb
149
+ - lib/woods/console/tool_specs.rb
103
150
  - lib/woods/console/tools/tier1.rb
104
151
  - lib/woods/console/tools/tier2.rb
105
152
  - lib/woods/console/tools/tier3.rb
@@ -123,6 +170,7 @@ files:
123
170
  - lib/woods/embedding/openai.rb
124
171
  - lib/woods/embedding/provider.rb
125
172
  - lib/woods/embedding/text_preparer.rb
173
+ - lib/woods/embedding/token_counter.rb
126
174
  - lib/woods/evaluation/baseline_runner.rb
127
175
  - lib/woods/evaluation/evaluator.rb
128
176
  - lib/woods/evaluation/metrics.rb
@@ -159,6 +207,7 @@ files:
159
207
  - lib/woods/extractors/rails_source_extractor.rb
160
208
  - lib/woods/extractors/rake_task_extractor.rb
161
209
  - lib/woods/extractors/route_extractor.rb
210
+ - lib/woods/extractors/route_helper_resolver.rb
162
211
  - lib/woods/extractors/scheduled_job_extractor.rb
163
212
  - lib/woods/extractors/serializer_extractor.rb
164
213
  - lib/woods/extractors/service_extractor.rb
@@ -168,6 +217,8 @@ files:
168
217
  - lib/woods/extractors/test_mapping_extractor.rb
169
218
  - lib/woods/extractors/validator_extractor.rb
170
219
  - lib/woods/extractors/view_component_extractor.rb
220
+ - lib/woods/extractors/view_engines/base.rb
221
+ - lib/woods/extractors/view_engines/erb.rb
171
222
  - lib/woods/extractors/view_template_extractor.rb
172
223
  - lib/woods/feedback/gap_detector.rb
173
224
  - lib/woods/feedback/store.rb
@@ -183,8 +234,15 @@ files:
183
234
  - lib/woods/formatting/gpt_adapter.rb
184
235
  - lib/woods/formatting/human_adapter.rb
185
236
  - lib/woods/graph_analyzer.rb
237
+ - lib/woods/index_artifact.rb
238
+ - lib/woods/mcp/bearer_auth.rb
239
+ - lib/woods/mcp/bootstrap_state.rb
186
240
  - lib/woods/mcp/bootstrapper.rb
241
+ - lib/woods/mcp/config_resolver.rb
242
+ - lib/woods/mcp/errors.rb
187
243
  - lib/woods/mcp/index_reader.rb
244
+ - lib/woods/mcp/origin_guard.rb
245
+ - lib/woods/mcp/provider_probe.rb
188
246
  - lib/woods/mcp/renderers/claude_renderer.rb
189
247
  - lib/woods/mcp/renderers/json_renderer.rb
190
248
  - lib/woods/mcp/renderers/markdown_renderer.rb
@@ -210,6 +268,7 @@ files:
210
268
  - lib/woods/resilience/circuit_breaker.rb
211
269
  - lib/woods/resilience/index_validator.rb
212
270
  - lib/woods/resilience/retryable_provider.rb
271
+ - lib/woods/resolved_config.rb
213
272
  - lib/woods/retrieval/context_assembler.rb
214
273
  - lib/woods/retrieval/query_classifier.rb
215
274
  - lib/woods/retrieval/ranker.rb
@@ -230,13 +289,23 @@ files:
230
289
  - lib/woods/session_tracer/solid_cache_store.rb
231
290
  - lib/woods/session_tracer/store.rb
232
291
  - lib/woods/storage/graph_store.rb
292
+ - lib/woods/storage/inapplicable_backend.rb
233
293
  - lib/woods/storage/metadata_store.rb
234
294
  - lib/woods/storage/pgvector.rb
235
295
  - lib/woods/storage/qdrant.rb
296
+ - lib/woods/storage/snapshotter.rb
297
+ - lib/woods/storage/snapshotter/metadata.rb
298
+ - lib/woods/storage/snapshotter/vector.rb
236
299
  - lib/woods/storage/vector_store.rb
300
+ - lib/woods/tasks.rb
237
301
  - lib/woods/temporal/json_snapshot_store.rb
238
302
  - lib/woods/temporal/snapshot_store.rb
239
303
  - lib/woods/token_utils.rb
304
+ - lib/woods/unblocked/client.rb
305
+ - lib/woods/unblocked/document_builder.rb
306
+ - lib/woods/unblocked/exporter.rb
307
+ - lib/woods/unblocked/rate_limiter.rb
308
+ - lib/woods/util/host_guard.rb
240
309
  - lib/woods/version.rb
241
310
  homepage: https://github.com/lost-in-the/woods
242
311
  licenses: