rails-ai-bridge 4.1.0 → 4.2.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 +4 -4
- data/.mutant.yml +26 -0
- data/.rubocop.yml +9 -0
- data/AGENTS.md +5 -5
- data/CHANGELOG.md +27 -0
- data/CLAUDE.md +5 -5
- data/CONTRIBUTING.md +2 -2
- data/README.md +10 -9
- data/Rakefile +2 -0
- data/SECURITY.md +4 -4
- data/docs/02-port-registry-resolution.md +1 -1
- data/docs/devin-setup.md +2 -2
- data/docs/port-registry-resolution.md +1 -1
- data/docs/registry-resolution.md +3 -3
- data/docs/skill-registry-guide.md +8 -8
- data/lib/rails_ai_bridge/config/registry.rb +47 -4
- data/lib/rails_ai_bridge/context_provider.rb +1 -1
- data/lib/rails_ai_bridge/doctor/checkers/registry_checker.rb +135 -0
- data/lib/rails_ai_bridge/doctor.rb +2 -1
- data/lib/rails_ai_bridge/engine.rb +1 -0
- data/lib/rails_ai_bridge/instrumentation.rb +30 -1
- data/lib/rails_ai_bridge/introspectors/action_mailbox_introspector.rb +6 -0
- data/lib/rails_ai_bridge/introspectors/asset_pipeline_introspector.rb +7 -0
- data/lib/rails_ai_bridge/introspectors/database_stats_introspector.rb +8 -0
- data/lib/rails_ai_bridge/introspectors/devops_introspector.rb +7 -0
- data/lib/rails_ai_bridge/introspectors/i18n_introspector.rb +7 -0
- data/lib/rails_ai_bridge/introspectors/rake_task_introspector.rb +7 -0
- data/lib/rails_ai_bridge/introspectors/test_introspector.rb +8 -0
- data/lib/rails_ai_bridge/registry.rb +61 -1
- data/lib/rails_ai_bridge/resources.rb +87 -3
- data/lib/rails_ai_bridge/serializers/README.md +0 -1
- data/lib/rails_ai_bridge/serializers/json_serializer.rb +4 -0
- data/lib/rails_ai_bridge/serializers/providers/base_provider_serializer.rb +1 -1
- data/lib/rails_ai_bridge/server.rb +2 -1
- data/lib/rails_ai_bridge/tasks/rails_ai_bridge.rake +1 -1
- data/lib/rails_ai_bridge/tools/list_context_providers.rb +132 -0
- data/lib/rails_ai_bridge/tools/list_registry.rb +3 -3
- data/lib/rails_ai_bridge/tools/search_code.rb +31 -0
- data/lib/rails_ai_bridge/version.rb +1 -1
- data/lib/tasks/perf.rake +27 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 24c9dd6461240b9d6864b35c171c465635f9fdacc3c76195915f43b995a27f18
|
|
4
|
+
data.tar.gz: e97756c625478c854f78f661393d26043ba36b07b8941bed7a2a2c09b3a62a4b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f453227c44348be19356eecb728dac22328abcb20a99cf0430f441c68557346d93576527716764cae4f68f404fcab524dd44c4454b27a4f9078955632be8937f
|
|
7
|
+
data.tar.gz: 10e975098f252c37f37108e04d0e370b03f469829f9e2520334b180e83a8844a8276b9f4ed60ae650e0f9bd47dd7361b42885dcbdf87880e37d56c04152720fa
|
data/.mutant.yml
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Mutant configuration for rails-ai-bridge critical paths.
|
|
3
|
+
#
|
|
4
|
+
# Run with: BUNDLE_GEMFILE=Gemfile-mutation bundle exec mutant run [subject expressions]
|
|
5
|
+
# Example: BUNDLE_GEMFILE=Gemfile-mutation bundle exec mutant run RailsAiBridge::Registry::FrontmatterParser
|
|
6
|
+
#
|
|
7
|
+
# The open-source usage mode is used because rails-ai-bridge is an
|
|
8
|
+
# open-source project. A commercial license is required for private
|
|
9
|
+
# repositories or advanced features (full operator set, isolation).
|
|
10
|
+
#
|
|
11
|
+
# Target: >80% mutation coverage on registry/tools.
|
|
12
|
+
#
|
|
13
|
+
# Subject expressions are passed on the CLI to target critical paths:
|
|
14
|
+
# RailsAiBridge::Registry — registry resolution
|
|
15
|
+
# RailsAiBridge::Tools — MCP tools
|
|
16
|
+
# RailsAiBridge::Serializers — output serializers
|
|
17
|
+
usage: opensource
|
|
18
|
+
integration: rspec
|
|
19
|
+
includes:
|
|
20
|
+
- lib
|
|
21
|
+
- spec
|
|
22
|
+
requires:
|
|
23
|
+
- spec_helper
|
|
24
|
+
fail_fast: false
|
|
25
|
+
mutation:
|
|
26
|
+
timeout: 5.0
|
data/.rubocop.yml
CHANGED
|
@@ -9,6 +9,7 @@ AllCops:
|
|
|
9
9
|
- "vendor/**/*"
|
|
10
10
|
- "spec/internal/**/*"
|
|
11
11
|
- "gemfiles/**/*"
|
|
12
|
+
- ".mutant.yml"
|
|
12
13
|
Naming/FileName:
|
|
13
14
|
Exclude:
|
|
14
15
|
- "lib/rails-ai-bridge.rb"
|
|
@@ -39,6 +40,8 @@ Layout/LineLength:
|
|
|
39
40
|
Max: 180
|
|
40
41
|
Metrics/ModuleLength:
|
|
41
42
|
Max: 240
|
|
43
|
+
Exclude:
|
|
44
|
+
- "lib/rails_ai_bridge/resources.rb"
|
|
42
45
|
Metrics/MethodLength:
|
|
43
46
|
Max: 70
|
|
44
47
|
RSpec/NestedGroups:
|
|
@@ -57,6 +60,12 @@ RSpec/MultipleDescribes:
|
|
|
57
60
|
Enabled: false
|
|
58
61
|
RSpec/MessageSpies:
|
|
59
62
|
Enabled: false
|
|
63
|
+
RSpec/Output:
|
|
64
|
+
Exclude:
|
|
65
|
+
- "spec/support/perf_baseline.rb"
|
|
66
|
+
Rails/RakeEnvironment:
|
|
67
|
+
Exclude:
|
|
68
|
+
- "lib/tasks/*.rake"
|
|
60
69
|
Metrics/PerceivedComplexity:
|
|
61
70
|
Max: 35
|
|
62
71
|
Exclude:
|
data/AGENTS.md
CHANGED
|
@@ -8,9 +8,9 @@ structure to AI assistants via the Model Context Protocol (MCP).
|
|
|
8
8
|
- `lib/rails_ai_bridge.rb` — Main entry point, public API (Zeitwerk autoloaded)
|
|
9
9
|
- `lib/rails_ai_bridge/configuration.rb` — User-facing config with presets (:standard, :full)
|
|
10
10
|
- `lib/rails_ai_bridge/introspector.rb` — Orchestrates sub-introspectors
|
|
11
|
-
- `lib/rails_ai_bridge/introspectors/` — Built-in introspector classes; `:standard` preset runs **9**, `:full` runs **
|
|
12
|
-
- `lib/rails_ai_bridge/tools/` —
|
|
13
|
-
- `lib/rails_ai_bridge/serializers/` — Output formatters (
|
|
11
|
+
- `lib/rails_ai_bridge/introspectors/` — Built-in introspector classes; `:standard` preset runs **9**, `:full` runs **27** (see `Configuration::PRESETS`). Registry: `Introspector::BUILTIN_INTROSPECTORS` (includes opt-in symbols such as `database_stats`, `non_ar_models` not listed in those presets).
|
|
12
|
+
- `lib/rails_ai_bridge/tools/` — 17 built-in MCP tools using the official mcp SDK (hosts can add more via `additional_tools`)
|
|
13
|
+
- `lib/rails_ai_bridge/serializers/` — Output formatters (claude, claude_rules, codex, cursor_rules, devin, devin_rules, copilot, copilot_instructions, gemini, rules, markdown, JSON)
|
|
14
14
|
- `lib/rails_ai_bridge/resources.rb` — MCP resources (static data AI clients read directly)
|
|
15
15
|
- `lib/rails_ai_bridge/server.rb` — MCP server configuration (stdio + HTTP transports)
|
|
16
16
|
- `lib/rails_ai_bridge/middleware.rb` — Rack middleware for auto-mounting MCP HTTP endpoint
|
|
@@ -30,10 +30,10 @@ structure to AI assistants via the Model Context Protocol (MCP).
|
|
|
30
30
|
6. **Diff-aware** — context regeneration skips unchanged files
|
|
31
31
|
7. **Per-assistant serializers** — each AI tool gets tailored output format
|
|
32
32
|
8. **Zeitwerk autoloading** — files loaded on-demand, not all upfront
|
|
33
|
-
9. **Introspector presets** — `:standard` (9 core) default, `:full` (
|
|
33
|
+
9. **Introspector presets** — `:standard` (9 core) default, `:full` (27 introspectors; optional extras such as `database_stats`, `non_ar_models`) for power users
|
|
34
34
|
10. **MCP auto-discovery** — `.mcp.json` generated by install generator
|
|
35
35
|
11. **Compact by default** — context files ≤150 lines, MCP tools use `detail` parameter (summary/standard/full)
|
|
36
|
-
12. **Per-tool split rules** — `.
|
|
36
|
+
12. **Per-tool split rules** — `.codex/`, `.cursor/rules/`, `.devin/rules/`, `.github/instructions/`
|
|
37
37
|
|
|
38
38
|
## Testing
|
|
39
39
|
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,33 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [4.2.0] - 2026-08-13
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`rails_list_context_providers` MCP tool and dynamic resources** (#147) — new tool reads the registry manifest's `context_providers` section and returns formatted markdown with provider name, type, endpoint, optional flag, and tool specs. Context providers are also registered as dynamic MCP resources (URI template `rails://context-providers/{name}`), bringing the tool count from 16 to 17.
|
|
13
|
+
- **Registry health checker for Doctor** (#145) — new `Doctor::Checkers::RegistryChecker` validates manifest existence, JSON parsing, `RegistryManifest.validate!`, resolver construction, and lockfile presence (when configured). Returns pass/warn/fail with actionable fix hints. Doctor check count: 17.
|
|
14
|
+
- **Request-level resolver memoization** (#159) — `Registry.with_request_resolver` wraps each tool invocation in a thread-local request scope so `build_resolver` is called once per request instead of once per tool. Nil results are never memoized; thread-local storage is always cleaned up (even on error).
|
|
15
|
+
- **Dependabot configuration** (#153) — `.github/dependabot.yml` with grouped updates for bundler, github-actions, and gomod ecosystems, plus automatic PR labeling.
|
|
16
|
+
- **Rails 8.1 in release workflow matrix** (#164) — `.github/workflows/release.yml` now includes Rails 8.1 alongside 7.1, 7.2, and 8.0.
|
|
17
|
+
- **Skunk score threshold CI job** (#157) — advisory CI job runs `skunk lib/` after tests generate coverage data, fails if the SkunkScore average exceeds 30. Threshold to be ratcheted down over time.
|
|
18
|
+
- **Performance regression baseline** (#160) — `spec/support/perf_baseline.json` with three metrics (introspection, context generation, MCP tool response). `rake perf:compare` fails on >20% regression. CI uploads the baseline as a 30-day artifact.
|
|
19
|
+
- **Mutation testing for critical paths** (#163) — `mutant-rspec` via separate `Gemfile-mutation` (eval'd from the main Gemfile) to avoid breaking Ruby 3.2 CI resolution. Advisory CI job targets `Registry::Resolver`, `FrontmatterParser`, `RegistryManifest`, `PackResolver`, `SkillSourceResolver`, and key tools/serializers. Initial coverage: 94.39% on `FrontmatterParser`.
|
|
20
|
+
- **YARD documentation for 9 uncovered files** (#156) — `@param`/`@return` tags added to `search_code.rb`, all 6 introspectors, `json_serializer.rb`, and `usage_formatter.rb`. `yard stats` now 100% for `lib/`.
|
|
21
|
+
- **Dedicated `UsageFormatter` spec** (#151) — comprehensive spec coverage for `Tools::UsageFormatter` formatting logic.
|
|
22
|
+
- **Registry server specs and integration tests** (#149, #150) — `server_spec.rb` extended with registry tool assertions; new `mcp/registry_integration_spec.rb` covers `rails_list_registry`, `rails_resolve_skill`, and `rails_use_skill` end-to-end through the MCP server.
|
|
23
|
+
- **Documentation parity guard spec** — `spec/lib/rails_ai_bridge/doc_parity_spec.rb` fails when README/AGENTS/CLAUDE tool or introspector counts drift from the actual constants.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- **Standardized registry manifest and lockfile paths** (#155) — defaults changed from `config/rails_ai_bridge_registry.json` / `config/rails_ai_bridge_registry.lock` to `config/rails_ai_bridge/registry.json` / `config/rails_ai_bridge/registry.lock`. Backward-compat fallback: when the new path doesn't exist but the legacy path does, the getter returns the legacy path. Custom user paths are never overridden.
|
|
28
|
+
- **Documentation humanization and Windsurf purge** (#144, #148) — README, AGENTS.md, CLAUDE.md, CONTRIBUTING.md, and SECURITY.md updated: tool count 16→17, introspector count 26→27, serializer list humanized (alphabetical with Claude/Codex/Gemini), bogus `.Codex/rules/` path fixed to `.codex/`, Windsurf support claims removed (no serializer will be implemented), Mermaid diagrams added to docs.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- **`Instrumentation::InstrumentedTool` server_context parameter translation** — tools without caching received `server_context:` but expected `_server_context:`, causing `ArgumentError` when caching was disabled. `InstrumentedTool` now detects the tool's parameter name and translates accordingly.
|
|
33
|
+
- **`ContextProvider` cache key fork safety** (#162) — replaced `object_id`-based cache key with a stable digest, preventing stale cache hits after `Process.fork`.
|
|
34
|
+
|
|
8
35
|
## [4.1.0] - 2026-08-11
|
|
9
36
|
|
|
10
37
|
### Added
|
data/CLAUDE.md
CHANGED
|
@@ -9,14 +9,14 @@ structure to AI assistants via the Model Context Protocol (MCP).
|
|
|
9
9
|
- `lib/rails_ai_bridge/configuration.rb` — User-facing config with presets (:standard, :full)
|
|
10
10
|
- `lib/rails_ai_bridge/introspector.rb` — Orchestrates sub-introspectors
|
|
11
11
|
- `lib/rails_ai_bridge/introspectors/` — Built-in introspector classes; `:standard` preset
|
|
12
|
-
runs **9**, `:full` runs **
|
|
12
|
+
runs **9**, `:full` runs **27** (see `Configuration::PRESETS`). Registry:
|
|
13
13
|
`Introspector::BUILTIN_INTROSPECTORS` (includes opt-in symbols such as
|
|
14
14
|
`database_stats`, `non_ar_models` not listed in those presets).
|
|
15
|
-
- `lib/rails_ai_bridge/tools/` —
|
|
15
|
+
- `lib/rails_ai_bridge/tools/` — 17 built-in MCP tools using the official mcp SDK
|
|
16
16
|
(hosts can add more via `additional_tools`)
|
|
17
17
|
- `lib/rails_ai_bridge/serializers/` — Output formatters (claude, claude_rules,
|
|
18
|
-
cursor_rules, devin, devin_rules, copilot, copilot_instructions,
|
|
19
|
-
markdown, JSON)
|
|
18
|
+
codex, cursor_rules, devin, devin_rules, copilot, copilot_instructions,
|
|
19
|
+
gemini, rules, markdown, JSON)
|
|
20
20
|
- `lib/rails_ai_bridge/resources.rb` — MCP resources (static data AI clients read directly)
|
|
21
21
|
- `lib/rails_ai_bridge/server.rb` — MCP server configuration (stdio + HTTP transports)
|
|
22
22
|
- `lib/rails_ai_bridge/middleware.rb` — Rack middleware for auto-mounting MCP HTTP endpoint
|
|
@@ -36,7 +36,7 @@ structure to AI assistants via the Model Context Protocol (MCP).
|
|
|
36
36
|
6. **Diff-aware** — context regeneration skips unchanged files
|
|
37
37
|
7. **Per-assistant serializers** — each AI tool gets tailored output format
|
|
38
38
|
8. **Zeitwerk autoloading** — files loaded on-demand, not all upfront
|
|
39
|
-
9. **Introspector presets** — `:standard` (9 core) default, `:full` (
|
|
39
|
+
9. **Introspector presets** — `:standard` (9 core) default, `:full` (27 introspectors; optional extras such as `database_stats`, `non_ar_models`) for power users
|
|
40
40
|
10. **MCP auto-discovery** — `.mcp.json` generated by install generator
|
|
41
41
|
11. **Compact by default** — context files ≤150 lines, MCP tools use `detail` parameter (summary/standard/full)
|
|
42
42
|
12. **Per-tool split rules** — `.claude/rules/`, `.cursor/rules/`, `.devin/rules/`, `.github/instructions/`
|
data/CONTRIBUTING.md
CHANGED
|
@@ -19,13 +19,13 @@ The test suite uses [Combustion](https://github.com/pat/combustion) to boot a mi
|
|
|
19
19
|
```
|
|
20
20
|
lib/rails_ai_bridge/
|
|
21
21
|
├── introspectors/ # Built-in introspectors (schema, models, non_ar_models, routes, …)
|
|
22
|
-
├── tools/ #
|
|
22
|
+
├── tools/ # 17 built-in MCP tools (detail levels, pagination, extensible)
|
|
23
23
|
├── rubydex_adapter.rb # Rubydex API wrapper (singleton + query interface + stats)
|
|
24
24
|
├── rubydex_adapter/ # Extracted collaborators (one concern each)
|
|
25
25
|
│ ├── serializer.rb # Hash serialization (declaration_to_hash, definition_to_hash, …)
|
|
26
26
|
│ ├── indexer.rb # Graph building + source file scanning
|
|
27
27
|
│ └── method_counter.rb # Flat method counting pipeline (no nested conditionals)
|
|
28
|
-
├── serializers/ # Per-assistant formatters (claude, cursor,
|
|
28
|
+
├── serializers/ # Per-assistant formatters (claude, codex, cursor, devin, copilot, gemini, JSON)
|
|
29
29
|
├── server.rb # MCP server setup (stdio + HTTP)
|
|
30
30
|
├── engine.rb # Rails Engine for auto-integration
|
|
31
31
|
└── configuration.rb # User-facing config (presets, context_mode, limits)
|
data/README.md
CHANGED
|
@@ -83,7 +83,7 @@ This creates two complementary layers:
|
|
|
83
83
|
| Static files | Give the assistant passive project orientation at session start | Fewer cold starts and fewer generic assumptions |
|
|
84
84
|
| MCP tools | Return exact live details when requested | Less context bloat and fewer schema/route hallucinations |
|
|
85
85
|
|
|
86
|
-
Compact files are ordered for usefulness: primary domain models, busy endpoints, recently migrated tables, and optional hot-table
|
|
86
|
+
Compact files are ordered for usefulness: primary domain models, busy endpoints, recently migrated tables, and optional hot-table hints appear before less important details.
|
|
87
87
|
|
|
88
88
|
## Safety model
|
|
89
89
|
|
|
@@ -159,7 +159,7 @@ Optional: `gem install rails-ai-bridge` installs the gem into your Ruby environm
|
|
|
159
159
|
| Zero config | Yes — Railtie + install generator | No — per-project `projects.yml` | No |
|
|
160
160
|
| Token optimization | Yes — compact files + `detail:"summary"` workflow | Varies | No |
|
|
161
161
|
| Codex-oriented repo files | Yes — `AGENTS.md`, `.codex/README.md` | No | DIY |
|
|
162
|
-
| Live MCP tools | Yes —
|
|
162
|
+
| Live MCP tools | Yes — 17 read-only `rails_*` tools (extensible) | Yes | No |
|
|
163
163
|
| Auto-introspection | Yes — up to **27** domains (`:full`) | No — server points at projects you configure | DIY |
|
|
164
164
|
|
|
165
165
|
*Comparison reflects typical documented setups; verify against each project before treating any row as absolute.*
|
|
@@ -251,7 +251,7 @@ This keeps context focused and avoids unnecessary token usage while still allowi
|
|
|
251
251
|
|
|
252
252
|
## MCP Tools
|
|
253
253
|
|
|
254
|
-
The gem exposes **
|
|
254
|
+
The gem exposes **17 built-in tools** via MCP that AI clients call on-demand (hosts can append more via `config.additional_tools`):
|
|
255
255
|
|
|
256
256
|
| Tool | What it returns |
|
|
257
257
|
|------|----------------|
|
|
@@ -267,10 +267,11 @@ The gem exposes **16 built-in tools** via MCP that AI clients call on-demand (ho
|
|
|
267
267
|
| `rails_get_view` | View layouts, templates, partials; optional per-file detail under the configured `app/views` path |
|
|
268
268
|
| `rails_search_semantic` | Semantic code search using rubydex — find declarations by name with types, locations, and relationships |
|
|
269
269
|
| `rails_get_stimulus` | Stimulus controllers: targets, values, actions, outlets (requires `:stimulus` introspector) |
|
|
270
|
-
| `rails_list_registry` | Skill pack catalog — list skills, agents, or active packs; requires `config/
|
|
270
|
+
| `rails_list_registry` | Skill pack catalog — list skills, agents, or active packs; requires `config/rails_ai_bridge/registry.json` |
|
|
271
271
|
| `rails_resolve_skill` | Full content of a named skill or agent from the registry (priority ordering + deprecation redirects); optional `pack=` pin and `type=agent` |
|
|
272
272
|
| `rails_use_skill` | Loads a skill framed as an application directive (apply it step by step to the current task) |
|
|
273
273
|
| `rails_use_agent` | Loads an agent/workflow framed as an activation directive (follow it end to end) |
|
|
274
|
+
| `rails_list_context_providers` | Context providers declared in the registry manifest — external services (e.g. MCP servers) the bridge can query for project context; shows type, endpoint, optional flag, and tool specs |
|
|
274
275
|
|
|
275
276
|
All tools are **read-only** — they never modify your application or database.
|
|
276
277
|
|
|
@@ -307,7 +308,7 @@ A safety net (`max_tool_response_chars`, default 120K) truncates oversized respo
|
|
|
307
308
|
|
|
308
309
|
Early project-level trials suggest the biggest improvement is not always dramatic token reduction by itself. In several runs, `rails-ai-bridge` led to faster, more focused responses even when total token usage only dropped modestly.
|
|
309
310
|
|
|
310
|
-
This
|
|
311
|
+
This makes sense: compact assistant-specific files and the summary-first MCP workflow help the model find relevant code faster and start with better context.
|
|
311
312
|
|
|
312
313
|
Observed benefits so far:
|
|
313
314
|
- Less exploratory reading before the assistant reaches the relevant files
|
|
@@ -543,7 +544,7 @@ end
|
|
|
543
544
|
| `parallel_introspection` | `false` | Run introspectors concurrently (requires `concurrent-ruby`, which is already a Rails dependency) |
|
|
544
545
|
| `parallel_pool_size` | `4` | Max threads in the parallel pool; capped at the number of active introspectors so no idle threads are created |
|
|
545
546
|
| `parallel_timeout_seconds` | `10` | Per-introspector future timeout (seconds); timed-out introspectors return `{ error: "timed out after Ns" }` without blocking the others |
|
|
546
|
-
| `registry.registry_manifest_path` | `"config/
|
|
547
|
+
| `registry.registry_manifest_path` | `"config/rails_ai_bridge/registry.json"` | Path to the registry manifest JSON file for skill pack resolution |
|
|
547
548
|
| `registry.skill_cache_dir` | `"~/.rails-ai-bridge/cache"` | Directory for caching git repositories containing skill packs |
|
|
548
549
|
| `registry.skill_packs` | `nil` | Explicit pack names to load, or `nil` for auto-detection based on framework |
|
|
549
550
|
| `registry.local_registry_paths` | `[]` | Local directory paths (must contain `directory.json`) loaded at priority 0 |
|
|
@@ -686,10 +687,10 @@ To customize it in your initializer (`config/initializers/rails_ai_bridge.rb`):
|
|
|
686
687
|
rails-ai-bridge can load **skill packs** — shared collections of agent instructions — from versioned git repositories and surface them through `rails_list_registry` and rake tasks.
|
|
687
688
|
|
|
688
689
|
```ruby
|
|
689
|
-
config.registry.registry_manifest_path = "config/
|
|
690
|
+
config.registry.registry_manifest_path = "config/rails_ai_bridge/registry.json"
|
|
690
691
|
```
|
|
691
692
|
|
|
692
|
-
Quick example manifest (`config/
|
|
693
|
+
Quick example manifest (`config/rails_ai_bridge/registry.json`):
|
|
693
694
|
|
|
694
695
|
```json
|
|
695
696
|
{
|
|
@@ -835,7 +836,7 @@ Bug reports and pull requests: [github.com/igmarin/rails-ai-bridge/issues](https
|
|
|
835
836
|
|
|
836
837
|
## Acknowledgments & Origins
|
|
837
838
|
|
|
838
|
-
This gem ships as **rails-ai-bridge** (Ruby **`RailsAiBridge`**, version **4.
|
|
839
|
+
This gem ships as **rails-ai-bridge** (Ruby **`RailsAiBridge`**, version **4.2.0**). Earlier iterations of the same codebase were distributed as `rails-ai-context`.
|
|
839
840
|
|
|
840
841
|
RailsMCP evolved from
|
|
841
842
|
[crisnahine/rails-ai-context](https://github.com/crisnahine/rails-ai-context),
|
data/Rakefile
CHANGED
data/SECURITY.md
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
| Version | Supported |
|
|
6
6
|
|---------|--------------------|
|
|
7
|
-
|
|
|
8
|
-
| 3.
|
|
9
|
-
| 3.0.x–3.
|
|
10
|
-
| 2.x | :x: (end of life — upgrade to
|
|
7
|
+
| 4.x | :white_check_mark: |
|
|
8
|
+
| 3.6.x | :white_check_mark: (security fixes best-effort) |
|
|
9
|
+
| 3.0.x–3.5.x | :warning: (best-effort) |
|
|
10
|
+
| 2.x | :x: (end of life — upgrade to 4.x) |
|
|
11
11
|
| 1.x | :x: |
|
|
12
12
|
| < 1.0 | :x: |
|
|
13
13
|
|
|
@@ -96,7 +96,7 @@ end
|
|
|
96
96
|
### 3. Configuration
|
|
97
97
|
|
|
98
98
|
**Add to `lib/rails_ai_bridge/configuration.rb`:**
|
|
99
|
-
- `registry_manifest_path` — Path to registry.json (default: `config/
|
|
99
|
+
- `registry_manifest_path` — Path to registry.json (default: `config/rails_ai_bridge/registry.json`)
|
|
100
100
|
- `skill_cache_dir` — Path to git cache directory (default: `~/.rails-ai-bridge/cache`)
|
|
101
101
|
- `skill_packs` — Array of explicit pack names to load (optional)
|
|
102
102
|
- `local_registry_paths` — Array of local registry directories (optional)
|
data/docs/devin-setup.md
CHANGED
|
@@ -226,7 +226,7 @@ rails-ai-bridge supports a skill registry — a collection of reusable AI skills
|
|
|
226
226
|
|
|
227
227
|
The `rails_list_registry` tool returns all available skills. The `rails_resolve_skill` tool retrieves the full content of a named skill so Devin can apply it.
|
|
228
228
|
|
|
229
|
-
Skills are configured via `config/
|
|
229
|
+
Skills are configured via `config/rails_ai_bridge/registry.json` in your Rails application. A minimal registry file looks like:
|
|
230
230
|
|
|
231
231
|
```json
|
|
232
232
|
{
|
|
@@ -261,4 +261,4 @@ Devin will call `rails_list_registry`, review the options, and call `rails_resol
|
|
|
261
261
|
| `.devin/rules/rails-mcp-tools.md` | `rails ai:bridge:devin` | Yes |
|
|
262
262
|
| `AGENTS.md` | `rails ai:bridge:devin` | Yes |
|
|
263
263
|
| `.devin/mcp.json` | Manual | Yes |
|
|
264
|
-
| `config/
|
|
264
|
+
| `config/rails_ai_bridge/registry.json` | Manual | Yes |
|
|
@@ -119,7 +119,7 @@ necessary for the future skill compiler feature.
|
|
|
119
119
|
|
|
120
120
|
**Files:**
|
|
121
121
|
- `lib/rails_ai_bridge/config/registry.rb` — `Config::Registry` sub-object
|
|
122
|
-
- `registry_manifest_path` (default: `config/
|
|
122
|
+
- `registry_manifest_path` (default: `config/rails_ai_bridge/registry.json`)
|
|
123
123
|
- `skill_cache_dir` (default: `~/.rails-ai-bridge/cache`)
|
|
124
124
|
- `skill_packs` (default: `nil` — triggers auto-detection)
|
|
125
125
|
- `local_registry_paths` (default: `[]`)
|
data/docs/registry-resolution.md
CHANGED
|
@@ -16,7 +16,7 @@ When a pack is loaded, its skills and agents appear in `rails_list_registry`, an
|
|
|
16
16
|
|
|
17
17
|
## Quick start
|
|
18
18
|
|
|
19
|
-
**1. Create the registry manifest** at `config/
|
|
19
|
+
**1. Create the registry manifest** at `config/rails_ai_bridge/registry.json`:
|
|
20
20
|
|
|
21
21
|
```json
|
|
22
22
|
{
|
|
@@ -39,7 +39,7 @@ When a pack is loaded, its skills and agents appear in `rails_list_registry`, an
|
|
|
39
39
|
|
|
40
40
|
```ruby
|
|
41
41
|
RailsAiBridge.configure do |config|
|
|
42
|
-
config.registry.registry_manifest_path = "config/
|
|
42
|
+
config.registry.registry_manifest_path = "config/rails_ai_bridge/registry.json"
|
|
43
43
|
end
|
|
44
44
|
```
|
|
45
45
|
|
|
@@ -102,7 +102,7 @@ All options live under `config.registry.*`:
|
|
|
102
102
|
|
|
103
103
|
| Option | Default | Description |
|
|
104
104
|
|--------|---------|-------------|
|
|
105
|
-
| `registry_manifest_path` | `"config/
|
|
105
|
+
| `registry_manifest_path` | `"config/rails_ai_bridge/registry.json"` | Path to the registry manifest JSON |
|
|
106
106
|
| `skill_cache_dir` | `~/.rails-ai-bridge/cache` | Directory for caching cloned git repositories |
|
|
107
107
|
| `skill_packs` | `nil` | Explicit list of pack names to load, or `nil` for auto-detection |
|
|
108
108
|
| `local_registry_paths` | `[]` | Local directory paths containing a `directory.json` (loaded at priority 0) |
|
|
@@ -18,7 +18,7 @@ A **skill pack** is a git repository containing:
|
|
|
18
18
|
- **Markdown files** for each skill (e.g. `skills/code-review.md`)
|
|
19
19
|
- Optional **deprecation redirects** when skills are renamed
|
|
20
20
|
|
|
21
|
-
The skill registry in your Rails app is a **`config/
|
|
21
|
+
The skill registry in your Rails app is a **`config/rails_ai_bridge/registry.json`** manifest that tells rails-ai-bridge which packs to load, where to find them, and how to prioritize them when two packs define a skill with the same name.
|
|
22
22
|
|
|
23
23
|
---
|
|
24
24
|
|
|
@@ -26,7 +26,7 @@ The skill registry in your Rails app is a **`config/rails_ai_bridge_registry.jso
|
|
|
26
26
|
|
|
27
27
|
### Step 1 — Create the registry manifest
|
|
28
28
|
|
|
29
|
-
Create `config/
|
|
29
|
+
Create `config/rails_ai_bridge/registry.json` in your Rails app:
|
|
30
30
|
|
|
31
31
|
```json
|
|
32
32
|
{
|
|
@@ -78,7 +78,7 @@ In `config/initializers/rails_ai_bridge.rb`:
|
|
|
78
78
|
|
|
79
79
|
```ruby
|
|
80
80
|
RailsAiBridge.configure do |config|
|
|
81
|
-
config.registry.registry_manifest_path = "config/
|
|
81
|
+
config.registry.registry_manifest_path = "config/rails_ai_bridge/registry.json"
|
|
82
82
|
end
|
|
83
83
|
```
|
|
84
84
|
|
|
@@ -195,13 +195,13 @@ This protects against:
|
|
|
195
195
|
rails ai:registry:lockfile
|
|
196
196
|
```
|
|
197
197
|
|
|
198
|
-
The file is written to `config/rails_ai_bridge/
|
|
198
|
+
The file is written to `config/rails_ai_bridge/registry.lock` by default. Commit it alongside your manifest.
|
|
199
199
|
|
|
200
200
|
### Configuration
|
|
201
201
|
|
|
202
202
|
```ruby
|
|
203
203
|
RailsAiBridge.configure do |config|
|
|
204
|
-
config.registry.lockfile_path = "config/rails_ai_bridge/
|
|
204
|
+
config.registry.lockfile_path = "config/rails_ai_bridge/registry.lock"
|
|
205
205
|
config.registry.lockfile_verification = :strict # :strict (default), :warn, or :disabled
|
|
206
206
|
end
|
|
207
207
|
```
|
|
@@ -438,7 +438,7 @@ initializer changes take effect immediately.
|
|
|
438
438
|
|
|
439
439
|
| Symptom | Likely cause | Fix |
|
|
440
440
|
|---------|-------------|-----|
|
|
441
|
-
| `rails ai:skills:list` shows "No registry manifest found" | Manifest file does not exist or path is wrong | Create `config/
|
|
441
|
+
| `rails ai:skills:list` shows "No registry manifest found" | Manifest file does not exist or path is wrong | Create `config/rails_ai_bridge/registry.json` or check `config.registry.registry_manifest_path` |
|
|
442
442
|
| Git clone fails with "not found" | Pack source URL is wrong or repo is private | Check the `source` field; for private repos use a full SSH URL `git@github.com:org/repo.git` |
|
|
443
443
|
| `Invalid source format` error mentioning `http://` | Pack source uses plain HTTP | Change `source` to `https://` or `git@` — plain HTTP is not accepted |
|
|
444
444
|
| Pack loads but shows 0 skills | `directory.json` is missing or has wrong path | Check the root of the cloned pack for `directory.json`; set `tile:` field if the file is elsewhere |
|
|
@@ -446,7 +446,7 @@ initializer changes take effect immediately.
|
|
|
446
446
|
| Stale skills after pack update | Resolver cache is warm or pull TTL has not elapsed | Run `rails ai:skills:clear_cache` to force a re-clone on the next build |
|
|
447
447
|
| Pack is not re-fetched even after `resolver_ttl` expired | Pack was cloned recently — `git_pull_ttl` (24 h) is still fresh | Run `rails ai:skills:clear_cache` or set `git_pull_ttl: 0` temporarily |
|
|
448
448
|
| `git checkout <ref>` failed | Invalid ref or detached HEAD issue | Verify the `ref` value matches a branch, tag, or SHA in the remote repo |
|
|
449
|
-
| `Lockfile mismatch for pack '…'` | Resolved pack commit differs from `
|
|
449
|
+
| `Lockfile mismatch for pack '…'` | Resolved pack commit differs from `registry.lock` | Run `rails ai:registry:lockfile` to update the lockfile after reviewing the pack changes |
|
|
450
450
|
| Git operation hangs / server request times out | Slow or unreachable remote | Reduce `git_timeout` to fail faster; check network connectivity to the remote |
|
|
451
451
|
| Warning: "Pack '…' depends on '…' which is not in the active pack set" | A loaded pack has an unsatisfied `depends_on` entry | Add the missing pack name to `always_loaded` or `skill_packs` in your manifest, or enable `config.registry.auto_load_dependencies` |
|
|
452
452
|
| Warning: "Circular dependency detected: …" | Two or more active packs depend on each other | Break the cycle in the manifests; packs still load, but the cycle usually indicates a mistake |
|
|
@@ -462,5 +462,5 @@ initializer changes take effect immediately.
|
|
|
462
462
|
- **Timeout protection**: all git operations are bounded by `git_timeout` (default 30 s) so a slow remote cannot block the calling thread indefinitely.
|
|
463
463
|
- **Cache key sanitization**: local cache directory names are derived from a sanitized source string plus a SHA256 hash suffix to prevent filesystem collisions.
|
|
464
464
|
- **Stable local pack names**: local registry pack names use a SHA256 digest of the directory path, so reordering `local_registry_paths` cannot silently shift pack identities.
|
|
465
|
-
- **Lockfile verification**: a `
|
|
465
|
+
- **Lockfile verification**: a `registry.lock` records the expected commit SHA for each remote pack. The resolver fails closed when the cloned commit does not match, preventing a compromised or unexpectedly modified pack from injecting instructions.
|
|
466
466
|
- **Local path trust**: local paths are used directly without git operations. The path traversal guard in the Resolver still applies to file reads within a local pack.
|
|
@@ -11,8 +11,20 @@ module RailsAiBridge
|
|
|
11
11
|
# @see RailsAiBridge::Registry::PackResolver
|
|
12
12
|
# @see RailsAiBridge::Registry::Resolver
|
|
13
13
|
class Registry
|
|
14
|
+
# Default path for the registry manifest (4.2.0+ standard location).
|
|
15
|
+
DEFAULT_REGISTRY_MANIFEST_PATH = 'config/rails_ai_bridge/registry.json'
|
|
16
|
+
|
|
17
|
+
# Legacy manifest path used before 4.2.0; kept for backward-compat fallback.
|
|
18
|
+
LEGACY_REGISTRY_MANIFEST_PATH = 'config/rails_ai_bridge_registry.json'
|
|
19
|
+
|
|
20
|
+
# Default path for the skill pack lockfile (4.2.0+ standard location).
|
|
21
|
+
DEFAULT_LOCKFILE_PATH = 'config/rails_ai_bridge/registry.lock'
|
|
22
|
+
|
|
23
|
+
# Legacy lockfile path used before 4.2.0; kept for backward-compat fallback.
|
|
24
|
+
LEGACY_LOCKFILE_PATH = 'config/rails_ai_bridge/directory.lock'
|
|
25
|
+
|
|
14
26
|
# @return [String] path to the registry manifest JSON file
|
|
15
|
-
|
|
27
|
+
attr_writer :registry_manifest_path
|
|
16
28
|
|
|
17
29
|
# @return [String] directory for caching git repositories
|
|
18
30
|
attr_accessor :skill_cache_dir
|
|
@@ -36,7 +48,38 @@ module RailsAiBridge
|
|
|
36
48
|
attr_reader :git_timeout
|
|
37
49
|
|
|
38
50
|
# @return [String, nil] path to the skill pack lockfile. nil disables lockfile verification.
|
|
39
|
-
|
|
51
|
+
attr_writer :lockfile_path
|
|
52
|
+
|
|
53
|
+
# Returns the configured registry manifest path, applying a backward-compatibility
|
|
54
|
+
# fallback when the default path does not exist but the legacy path does.
|
|
55
|
+
#
|
|
56
|
+
# @return [String] resolved manifest path
|
|
57
|
+
def registry_manifest_path
|
|
58
|
+
return @registry_manifest_path unless @registry_manifest_path == DEFAULT_REGISTRY_MANIFEST_PATH
|
|
59
|
+
|
|
60
|
+
File.exist?(DEFAULT_REGISTRY_MANIFEST_PATH) ? DEFAULT_REGISTRY_MANIFEST_PATH : legacy_manifest_path
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Returns the configured lockfile path, applying a backward-compatibility
|
|
64
|
+
# fallback when the default path does not exist but the legacy path does.
|
|
65
|
+
# Returns +nil+ when lockfile verification is disabled.
|
|
66
|
+
#
|
|
67
|
+
# @return [String, nil] resolved lockfile path
|
|
68
|
+
def lockfile_path
|
|
69
|
+
return @lockfile_path unless @lockfile_path == DEFAULT_LOCKFILE_PATH
|
|
70
|
+
|
|
71
|
+
File.exist?(DEFAULT_LOCKFILE_PATH) ? DEFAULT_LOCKFILE_PATH : legacy_lockfile_path
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @api private
|
|
75
|
+
def legacy_manifest_path
|
|
76
|
+
File.exist?(LEGACY_REGISTRY_MANIFEST_PATH) ? LEGACY_REGISTRY_MANIFEST_PATH : DEFAULT_REGISTRY_MANIFEST_PATH
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# @api private
|
|
80
|
+
def legacy_lockfile_path
|
|
81
|
+
File.exist?(LEGACY_LOCKFILE_PATH) ? LEGACY_LOCKFILE_PATH : DEFAULT_LOCKFILE_PATH
|
|
82
|
+
end
|
|
40
83
|
|
|
41
84
|
# @return [Symbol] how to behave when the lockfile differs from the resolved pack:
|
|
42
85
|
# :strict (default) raises, :warn logs but proceeds, :disabled skips verification.
|
|
@@ -97,14 +140,14 @@ module RailsAiBridge
|
|
|
97
140
|
end
|
|
98
141
|
|
|
99
142
|
def initialize
|
|
100
|
-
@registry_manifest_path =
|
|
143
|
+
@registry_manifest_path = DEFAULT_REGISTRY_MANIFEST_PATH
|
|
101
144
|
@skill_cache_dir = File.expand_path('~/.rails-ai-bridge/cache')
|
|
102
145
|
@skill_packs = nil
|
|
103
146
|
@local_registry_paths = []
|
|
104
147
|
@resolver_ttl = 1800
|
|
105
148
|
@git_pull_ttl = 86_400
|
|
106
149
|
@git_timeout = 30
|
|
107
|
-
@lockfile_path =
|
|
150
|
+
@lockfile_path = DEFAULT_LOCKFILE_PATH
|
|
108
151
|
@lockfile_verification = :strict
|
|
109
152
|
@auto_load_dependencies = false
|
|
110
153
|
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RailsAiBridge
|
|
4
|
+
class Doctor
|
|
5
|
+
module Checkers
|
|
6
|
+
# Verifies the registry manifest is present, valid, and resolvable.
|
|
7
|
+
#
|
|
8
|
+
# Checks (in order):
|
|
9
|
+
# 1. The configured +registry_manifest_path+ exists.
|
|
10
|
+
# 2. The manifest JSON parses successfully.
|
|
11
|
+
# 3. +RegistryManifest.validate!+ passes schema validation.
|
|
12
|
+
# 4. +Registry.build_resolver+ returns a non-nil resolver.
|
|
13
|
+
# 5. The lockfile exists and matches (when +lockfile_path+ is configured).
|
|
14
|
+
#
|
|
15
|
+
# Each failure short-circuits with an actionable fix hint so the user can
|
|
16
|
+
# resolve the first problem before chasing downstream symptoms.
|
|
17
|
+
class RegistryChecker < BaseChecker
|
|
18
|
+
# @return [Doctor::Check] +:pass+, +:warn+, or +:fail+
|
|
19
|
+
def call
|
|
20
|
+
return missing_manifest_check unless manifest_path_exists?
|
|
21
|
+
|
|
22
|
+
return invalid_json_check unless manifest_parses?
|
|
23
|
+
|
|
24
|
+
return validation_failed_check unless manifest_validates?
|
|
25
|
+
|
|
26
|
+
resolver = build_resolver
|
|
27
|
+
return resolver_failed_check(resolver) unless resolver
|
|
28
|
+
|
|
29
|
+
return lockfile_check if lockfile_configured? && !lockfile_exists?
|
|
30
|
+
|
|
31
|
+
new_check(name: 'Registry', status: :pass, message: 'Registry manifest is valid and resolvable', fix: nil)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def registry_config
|
|
37
|
+
RailsAiBridge.configuration.registry
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def manifest_path
|
|
41
|
+
registry_config.registry_manifest_path
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def manifest_path_exists?
|
|
45
|
+
File.exist?(manifest_path)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def missing_manifest_check
|
|
49
|
+
new_check(
|
|
50
|
+
name: 'Registry',
|
|
51
|
+
status: :warn,
|
|
52
|
+
message: "Registry manifest not found at `#{manifest_path}`",
|
|
53
|
+
fix: 'Create a registry manifest file — see docs/skill-registry-guide.md'
|
|
54
|
+
)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def manifest_parses?
|
|
58
|
+
parsed_manifest
|
|
59
|
+
true
|
|
60
|
+
rescue ArgumentError
|
|
61
|
+
false
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def invalid_json_check
|
|
65
|
+
new_check(
|
|
66
|
+
name: 'Registry',
|
|
67
|
+
status: :fail,
|
|
68
|
+
message: "Registry manifest at `#{manifest_path}` contains invalid JSON or could not be read",
|
|
69
|
+
fix: "Fix the JSON syntax in the manifest file — run `ruby -rjson -e 'JSON.parse(File.read(ARGV[0]))' #{manifest_path}` to see the parse error"
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def parsed_manifest
|
|
74
|
+
@parsed_manifest ||= RailsAiBridge::Registry::RegistryManifest.from_file(manifest_path)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def manifest_validates?
|
|
78
|
+
RailsAiBridge::Registry::RegistryManifest.validate!(raw_manifest_hash)
|
|
79
|
+
true
|
|
80
|
+
rescue RailsAiBridge::Registry::RegistryManifest::ValidationError
|
|
81
|
+
false
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def raw_manifest_hash
|
|
85
|
+
JSON.parse(File.read(manifest_path))
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def validation_failed_check
|
|
89
|
+
new_check(
|
|
90
|
+
name: 'Registry',
|
|
91
|
+
status: :fail,
|
|
92
|
+
message: "Registry manifest at `#{manifest_path}` failed schema validation",
|
|
93
|
+
fix: 'Check the manifest structure — see docs/skill-registry-guide.md for the expected schema'
|
|
94
|
+
)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def build_resolver
|
|
98
|
+
RailsAiBridge::Registry.build_resolver(registry_config)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def resolver_failed_check(resolver)
|
|
102
|
+
new_check(
|
|
103
|
+
name: 'Registry',
|
|
104
|
+
status: :warn,
|
|
105
|
+
message: "Registry manifest parsed but resolver returned nil#{resolver_reason(resolver)}",
|
|
106
|
+
fix: 'Check that all pack sources are reachable and git is available — see logs for details'
|
|
107
|
+
)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def resolver_reason(resolver)
|
|
111
|
+
return '' unless resolver.nil?
|
|
112
|
+
|
|
113
|
+
' (manifest missing or pack sources could not be resolved)'
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def lockfile_configured?
|
|
117
|
+
registry_config.lockfile_path
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def lockfile_exists?
|
|
121
|
+
File.exist?(registry_config.lockfile_path)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def lockfile_check
|
|
125
|
+
new_check(
|
|
126
|
+
name: 'Registry',
|
|
127
|
+
status: :warn,
|
|
128
|
+
message: "Lockfile not found at `#{registry_config.lockfile_path}`",
|
|
129
|
+
fix: 'Run `rails ai:registry:lock` to generate the lockfile, or set lockfile_path to nil to disable verification'
|
|
130
|
+
)
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|