@reinteractive/rails-insight 1.0.1
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.
- package/LICENSE +15 -0
- package/README.md +210 -0
- package/bin/railsinsight.js +128 -0
- package/package.json +62 -0
- package/src/core/blast-radius.js +496 -0
- package/src/core/constants.js +39 -0
- package/src/core/context-loader.js +227 -0
- package/src/core/drift-detector.js +168 -0
- package/src/core/formatter.js +197 -0
- package/src/core/graph.js +510 -0
- package/src/core/indexer.js +595 -0
- package/src/core/patterns/api.js +27 -0
- package/src/core/patterns/auth.js +25 -0
- package/src/core/patterns/authorization.js +24 -0
- package/src/core/patterns/caching.js +19 -0
- package/src/core/patterns/component.js +18 -0
- package/src/core/patterns/config.js +15 -0
- package/src/core/patterns/controller.js +42 -0
- package/src/core/patterns/email.js +20 -0
- package/src/core/patterns/factory.js +31 -0
- package/src/core/patterns/gemfile.js +9 -0
- package/src/core/patterns/helper.js +10 -0
- package/src/core/patterns/job.js +12 -0
- package/src/core/patterns/model.js +123 -0
- package/src/core/patterns/realtime.js +17 -0
- package/src/core/patterns/route.js +27 -0
- package/src/core/patterns/schema.js +25 -0
- package/src/core/patterns/stimulus.js +13 -0
- package/src/core/patterns/storage.js +16 -0
- package/src/core/patterns/uploader.js +16 -0
- package/src/core/patterns/view.js +20 -0
- package/src/core/patterns/worker.js +12 -0
- package/src/core/patterns.js +27 -0
- package/src/core/scanner.js +394 -0
- package/src/core/version-detector.js +295 -0
- package/src/extractors/api.js +284 -0
- package/src/extractors/auth.js +853 -0
- package/src/extractors/authorization.js +785 -0
- package/src/extractors/caching.js +84 -0
- package/src/extractors/component.js +221 -0
- package/src/extractors/config.js +81 -0
- package/src/extractors/controller.js +273 -0
- package/src/extractors/coverage-snapshot.js +296 -0
- package/src/extractors/email.js +123 -0
- package/src/extractors/factory-registry.js +225 -0
- package/src/extractors/gemfile.js +440 -0
- package/src/extractors/helper.js +55 -0
- package/src/extractors/jobs.js +122 -0
- package/src/extractors/model.js +506 -0
- package/src/extractors/realtime.js +102 -0
- package/src/extractors/routes.js +251 -0
- package/src/extractors/schema.js +178 -0
- package/src/extractors/stimulus.js +149 -0
- package/src/extractors/storage.js +100 -0
- package/src/extractors/test-conventions.js +340 -0
- package/src/extractors/tier2.js +417 -0
- package/src/extractors/tier3.js +84 -0
- package/src/extractors/uploader.js +138 -0
- package/src/extractors/views.js +131 -0
- package/src/extractors/worker.js +62 -0
- package/src/git/diff-parser.js +132 -0
- package/src/providers/interface.js +12 -0
- package/src/providers/local-fs.js +318 -0
- package/src/server.js +71 -0
- package/src/tools/blast-radius-tools.js +129 -0
- package/src/tools/free-tools.js +44 -0
- package/src/tools/handlers/get-controller.js +93 -0
- package/src/tools/handlers/get-coverage-gaps.js +100 -0
- package/src/tools/handlers/get-deep-analysis.js +294 -0
- package/src/tools/handlers/get-domain-clusters.js +113 -0
- package/src/tools/handlers/get-factory-registry.js +43 -0
- package/src/tools/handlers/get-full-index.js +28 -0
- package/src/tools/handlers/get-model.js +108 -0
- package/src/tools/handlers/get-overview.js +153 -0
- package/src/tools/handlers/get-routes.js +18 -0
- package/src/tools/handlers/get-schema.js +40 -0
- package/src/tools/handlers/get-subgraph.js +82 -0
- package/src/tools/handlers/get-test-conventions.js +18 -0
- package/src/tools/handlers/get-well-tested-examples.js +51 -0
- package/src/tools/handlers/helpers.js +115 -0
- package/src/tools/handlers/index-project.js +36 -0
- package/src/tools/handlers/search-patterns.js +104 -0
- package/src/tools/index.js +34 -0
- package/src/tools/pro-tools.js +13 -0
- package/src/utils/file-reader.js +20 -0
- package/src/utils/inflector.js +223 -0
- package/src/utils/ruby-parser.js +115 -0
- package/src/utils/spec-style-detector.js +26 -0
- package/src/utils/token-counter.js +46 -0
- package/src/utils/yaml-parser.js +135 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 reinteractive
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# RailsInsight
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@reinteractive/railsinsight)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
A Rails-aware codebase indexer that runs as an MCP (Model Context Protocol) server, giving AI coding agents deep structural understanding of your Rails application — models, associations, routes, schema, authentication, jobs, components, and 56 total file categories — without reading every file.
|
|
7
|
+
|
|
8
|
+
## Why RailsInsight?
|
|
9
|
+
|
|
10
|
+
Generic code-analysis tools treat Ruby files as plain text. RailsInsight understands **Rails conventions**: `has_many :through`, `before_action` filters, Devise modules, Pundit policies, Turbo Stream broadcasts, Solid Queue jobs, and more. It builds a directed weighted graph of your entire app and exposes it through MCP tools so your AI agent can reason about impact, dependencies, and architecture — without consuming your entire codebase in tokens.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx @reinteractive/railsinsight
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or install globally:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g @reinteractive/railsinsight
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
Run from your Rails project root:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx @reinteractive/railsinsight
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This starts a local MCP server over stdio. The indexer scans your project structure, extracts Rails conventions, builds a relationship graph, and exposes everything through MCP tools.
|
|
33
|
+
|
|
34
|
+
To point at a different Rails app:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx @reinteractive/railsinsight --project-root /path/to/your/rails/app
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### CLI Options
|
|
41
|
+
|
|
42
|
+
| Flag | Description |
|
|
43
|
+
| ----------------------- | ------------------------------------------------ |
|
|
44
|
+
| `--project-root <path>` | Path to the Rails project (defaults to cwd) |
|
|
45
|
+
| `--claude-md <path>` | Path to a `claude.md` / `CLAUDE.md` context file |
|
|
46
|
+
| `--mode local\|remote` | Transport mode (default: `local`) |
|
|
47
|
+
| `--port <number>` | Port for remote mode (default: `3000`) |
|
|
48
|
+
| `--verbose` | Enable verbose logging to stderr |
|
|
49
|
+
| `--help` | Show help |
|
|
50
|
+
|
|
51
|
+
## Claude Code Integration
|
|
52
|
+
|
|
53
|
+
Add to your Claude Code MCP configuration:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"mcpServers": {
|
|
58
|
+
"railsinsight": {
|
|
59
|
+
"command": "npx",
|
|
60
|
+
"args": ["@reinteractive/railsinsight"]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Cursor / VS Code Integration
|
|
67
|
+
|
|
68
|
+
In your `.cursor/mcp.json` or VS Code MCP settings:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"mcpServers": {
|
|
73
|
+
"railsinsight": {
|
|
74
|
+
"command": "npx",
|
|
75
|
+
"args": ["@reinteractive/railsinsight"]
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The server uses the workspace directory as the project root automatically, so no path argument is needed for normal project-local use.
|
|
82
|
+
|
|
83
|
+
## Available Tools
|
|
84
|
+
|
|
85
|
+
All 17 tools are available with no tier restrictions.
|
|
86
|
+
|
|
87
|
+
### Core Tools
|
|
88
|
+
|
|
89
|
+
| Tool | Description |
|
|
90
|
+
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
91
|
+
| `index_project` | Re-index the Rails project. In local mode, re-scans the project root. Accepts `force` (boolean) to bypass cache. Returns statistics and duration. |
|
|
92
|
+
| `get_overview` | Project summary: Rails/Ruby versions, database, auth strategy, key models and controllers, frontend stack, file counts. Call this first. |
|
|
93
|
+
| `get_full_index` | Complete index JSON trimmed to fit a specified token budget (default: 12,000 tokens). |
|
|
94
|
+
| `get_model` | Deep extraction for a specific model: associations, validations, scopes with queries, enums with values, callbacks, public methods, database columns. Requires `name`. |
|
|
95
|
+
| `get_controller` | Deep extraction for a specific controller: actions with routes, filters, rate limiting, strong params, rescue handlers. Requires `name`. |
|
|
96
|
+
| `get_routes` | Complete route map with namespaces, nested resources, member/collection routes. |
|
|
97
|
+
| `get_schema` | Database schema with tables, columns, indexes, foreign keys, and model-to-table mapping. |
|
|
98
|
+
| `get_subgraph` | Skill-scoped relationship subgraph with ranked files. Skills: `authentication`, `database`, `frontend`, `api`, `jobs`, `email`. |
|
|
99
|
+
| `search_patterns` | Search across all extractions for a specific Rails pattern type (e.g. `has_many_through`, `before_action`, `turbo_broadcast`). |
|
|
100
|
+
| `get_deep_analysis` | Deep analysis for a specific category. Categories: `authentication`, `authorization`, `jobs`, `email`, `storage`, `caching`, `realtime`, `api_patterns`, `dependencies`, `components`, `stimulus`, `views`, `convention_drift`, `manifest`, `detected_stack`, `related`, `model_list`, `controller_list`, `component_list`. Accepts optional `name` (entity name) and `depth` (BFS hops for `related`, default 2). |
|
|
101
|
+
|
|
102
|
+
### Test Intelligence Tools
|
|
103
|
+
|
|
104
|
+
| Tool | Description |
|
|
105
|
+
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
106
|
+
| `get_coverage_gaps` | Prioritised list of files needing test coverage, with structural context and per-method coverage data from SimpleCov. Accepts optional `category`, `min_gap`, and `limit`. |
|
|
107
|
+
| `get_test_conventions` | Detected test patterns and conventions: spec style (request vs controller), let style, auth helper, factories, shared examples, custom matchers, and pattern reference files. |
|
|
108
|
+
| `get_domain_clusters` | Domain-clustered file groups for parallel test generation. Files in the same cluster share associations and factories; different clusters can be worked on simultaneously. Accepts `max_cluster_size` and `include_covered`. |
|
|
109
|
+
| `get_factory_registry` | Parsed FactoryBot factory definitions including attributes, traits, sequences, and associations. Accepts optional `model` to filter by factory name. |
|
|
110
|
+
| `get_well_tested_examples` | High-quality existing spec files suitable as pattern references for test generation agents. Selected by structural complexity per spec category. Accepts `category` and `limit`. |
|
|
111
|
+
|
|
112
|
+
### Blast Radius Tools
|
|
113
|
+
|
|
114
|
+
| Tool | Description |
|
|
115
|
+
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
116
|
+
| `get_blast_radius` | Analyse the impact of code changes. Accepts explicit file paths or auto-detects from git diff. Returns impacted entities classified by risk level (CRITICAL/HIGH/MEDIUM/LOW) with affected tests. Accepts `files`, `base_ref`, `staged`, `max_depth`. |
|
|
117
|
+
| `get_review_context` | Build a token-budget-aware review summary for changed files. Combines blast radius analysis with relevant code context for AI-assisted code review. Accepts `files`, `base_ref`, `staged`, `token_budget`. |
|
|
118
|
+
|
|
119
|
+
## What It Detects
|
|
120
|
+
|
|
121
|
+
RailsInsight classifies files across **56 categories** using pure path-based analysis:
|
|
122
|
+
|
|
123
|
+
| # | Category | # | Category | # | Category |
|
|
124
|
+
| --- | -------------- | --- | ---------------- | --- | ------------------ |
|
|
125
|
+
| 1 | Models | 20 | Code Quality | 39 | Rich Text |
|
|
126
|
+
| 2 | Controllers | 21 | Deployment | 40 | Notifications |
|
|
127
|
+
| 3 | Routes | 22 | Search | 41 | Feature Flags |
|
|
128
|
+
| 4 | Schema | 23 | Payments | 42 | Audit |
|
|
129
|
+
| 5 | Components | 24 | Multi-tenancy | 43 | Soft Delete |
|
|
130
|
+
| 6 | Stimulus | 25 | Admin | 44 | Pagination |
|
|
131
|
+
| 7 | Views | 26 | Design Patterns | 45 | Friendly URLs |
|
|
132
|
+
| 8 | Authentication | 27 | State Machines | 46 | Tagging |
|
|
133
|
+
| 9 | Authorization | 28 | i18n | 47 | SEO |
|
|
134
|
+
| 10 | Jobs | 29 | PDF | 48 | Geolocation |
|
|
135
|
+
| 11 | Email | 30 | CSV | 49 | SMS / Push |
|
|
136
|
+
| 12 | Storage | 31 | Webhooks | 50 | Activity Tracking |
|
|
137
|
+
| 13 | Caching | 32 | Scheduled Tasks | 51 | Data Import/Export |
|
|
138
|
+
| 14 | Realtime | 33 | Middleware | 52 | Event Sourcing |
|
|
139
|
+
| 15 | API | 34 | Engines | 53 | dry-rb |
|
|
140
|
+
| 16 | Gemfile | 35 | Credentials | 54 | Markdown |
|
|
141
|
+
| 17 | Config | 36 | HTTP Client | 55 | Rate Limiting |
|
|
142
|
+
| 18 | Security | 37 | Performance | 56 | GraphQL |
|
|
143
|
+
| 19 | Testing | 38 | Database Tooling | | |
|
|
144
|
+
|
|
145
|
+
Beyond classification, deep extractors analyze file content to extract:
|
|
146
|
+
|
|
147
|
+
- **Models**: Associations, validations, scopes, enums, callbacks, concerns, Devise modules, broadcasts
|
|
148
|
+
- **Controllers**: Actions, before/after/around filters, strong params, rescue handlers, caching
|
|
149
|
+
- **Routes**: Resources, namespaces, nesting, member/collection routes, constraints, mounts
|
|
150
|
+
- **Schema**: Tables, columns with types, indexes (unique/composite), foreign keys
|
|
151
|
+
- **Components**: ViewComponent params, slots, Stimulus connections, sidecar files, previews
|
|
152
|
+
- **Auth**: Devise strategy, modules per model, custom controllers, OAuth providers
|
|
153
|
+
- **Authorization**: Pundit/CanCanCan policies, roles, permission structures
|
|
154
|
+
- **Jobs**: Queue names, retry strategies, callbacks, scheduling, Sidekiq/GoodJob config
|
|
155
|
+
- **Email**: Mailer actions, layouts, delivery config, Action Mailbox routing
|
|
156
|
+
- **Storage**: Active Storage services, model attachments, variants, direct upload config
|
|
157
|
+
- **Caching**: Cache store, fragment caching, Russian doll patterns, counter caches
|
|
158
|
+
- **Realtime**: ActionCable channels, Turbo Stream broadcasts, CableReady operations
|
|
159
|
+
- **API**: Versioning strategy, serializers, pagination, rate limiting, authentication
|
|
160
|
+
|
|
161
|
+
## Rails Version Support
|
|
162
|
+
|
|
163
|
+
| Rails Version | Support Level |
|
|
164
|
+
| ------------- | --------------------------------------------------------- |
|
|
165
|
+
| 8.0 – 8.1+ | Full support (Solid Queue, Solid Cache, Kamal, Propshaft) |
|
|
166
|
+
| 7.0 – 7.2 | Full support (Hotwire, import maps, Turbo) |
|
|
167
|
+
| 6.0 – 6.1 | Full support (Webpacker, Sprockets, legacy enum syntax) |
|
|
168
|
+
| < 6.0 | Basic structural scanning only |
|
|
169
|
+
|
|
170
|
+
## How It Works
|
|
171
|
+
|
|
172
|
+
RailsInsight processes your Rails project through a 6-layer pipeline:
|
|
173
|
+
|
|
174
|
+
1. **Context Loader** — Parses `claude.md` / `CLAUDE.md` for declared conventions and project context
|
|
175
|
+
2. **Version Detector** — Identifies Rails/Ruby versions, database adapter, asset pipeline, frontend stack, and all gems from `Gemfile.lock`
|
|
176
|
+
3. **Structural Scanner** — Classifies every file into 1 of 56 categories using path patterns (zero file reads)
|
|
177
|
+
4. **Deep Extractors** — 19 specialized extractors parse file content for models, controllers, routes, schema, components, Stimulus controllers, auth, authorization, jobs, email, storage, caching, realtime, API patterns, views, config, and tier 2/3 patterns
|
|
178
|
+
5. **Relationship Graph** — Builds a directed weighted graph with 22 edge types (model→association, controller→model, route→controller, etc.) and computes Personalized PageRank to rank entities by importance
|
|
179
|
+
6. **Convention Drift Detector** — Compares declared conventions (from `claude.md`) against actual extracted patterns, reporting mismatches with severity levels
|
|
180
|
+
|
|
181
|
+
The entire index is built in a single pass, typically under 2 seconds for large projects, and the result is served through MCP tools with token-budget-aware formatting.
|
|
182
|
+
|
|
183
|
+
## Contributing
|
|
184
|
+
|
|
185
|
+
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
186
|
+
|
|
187
|
+
### Running Tests
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
npm test # Run all tests
|
|
191
|
+
npm run test:watch # Watch mode
|
|
192
|
+
npm run test:core # Core layer tests only
|
|
193
|
+
npm run test:extractors # Extractor tests
|
|
194
|
+
npm run test:patterns # Rails pattern tests
|
|
195
|
+
npm run test:coverage # Run with coverage
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Limitations
|
|
199
|
+
|
|
200
|
+
RailsInsight uses regex-based extraction rather than a full Ruby AST parser. This handles the vast majority of real-world Rails code, but may miss unconventional patterns such as:
|
|
201
|
+
|
|
202
|
+
- Multi-line method calls split across 3+ lines
|
|
203
|
+
- Metaprogrammed associations or validations
|
|
204
|
+
- Dynamic class definitions
|
|
205
|
+
|
|
206
|
+
If you encounter a pattern that isn't detected, please [open an issue](https://github.com/reinteractive/rails-insight/issues).
|
|
207
|
+
|
|
208
|
+
## License
|
|
209
|
+
|
|
210
|
+
ISC — see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { parseArgs } from 'node:util'
|
|
4
|
+
import { existsSync } from 'node:fs'
|
|
5
|
+
import { resolve } from 'node:path'
|
|
6
|
+
import { pathToFileURL } from 'node:url'
|
|
7
|
+
|
|
8
|
+
const options = {
|
|
9
|
+
'project-root': { type: 'string', short: 'p' },
|
|
10
|
+
'claude-md': { type: 'string' },
|
|
11
|
+
mode: { type: 'string', short: 'm', default: 'local' },
|
|
12
|
+
port: { type: 'string', default: '3000' },
|
|
13
|
+
verbose: { type: 'boolean', short: 'v', default: false },
|
|
14
|
+
help: { type: 'boolean', short: 'h', default: false },
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const HELP_TEXT = `
|
|
18
|
+
RailsInsight — Rails-Aware Codebase Indexer (MCP Server)
|
|
19
|
+
|
|
20
|
+
Usage:
|
|
21
|
+
railsinsight --project-root <path> [options]
|
|
22
|
+
|
|
23
|
+
Options:
|
|
24
|
+
-p, --project-root <path> Path to Rails project root (required for local mode)
|
|
25
|
+
--claude-md <path> Path to claude.md file (defaults to {project-root}/claude.md)
|
|
26
|
+
-m, --mode <mode> Server mode: local or remote (default: local)
|
|
27
|
+
--port <number> Port for remote mode (default: 3000)
|
|
28
|
+
-v, --verbose Enable verbose logging to stderr
|
|
29
|
+
-h, --help Show this help message
|
|
30
|
+
|
|
31
|
+
Examples:
|
|
32
|
+
railsinsight --project-root /path/to/rails/app
|
|
33
|
+
railsinsight -p . --verbose
|
|
34
|
+
`
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Run the CLI with injectable dependencies for testing.
|
|
38
|
+
* @param {string[]} argv
|
|
39
|
+
* @param {Object} deps
|
|
40
|
+
* @returns {Promise<number>} Process exit code
|
|
41
|
+
*/
|
|
42
|
+
export async function main(argv = process.argv.slice(2), deps = {}) {
|
|
43
|
+
const writeStdout = deps.writeStdout || ((text) => process.stdout.write(text))
|
|
44
|
+
const writeStderr = deps.writeStderr || ((text) => process.stderr.write(text))
|
|
45
|
+
const parseArgsFn = deps.parseArgsFn || parseArgs
|
|
46
|
+
const existsSyncFn = deps.existsSyncFn || existsSync
|
|
47
|
+
const resolvePath = deps.resolvePath || resolve
|
|
48
|
+
const importServer = deps.importServer || (() => import('../src/server.js'))
|
|
49
|
+
|
|
50
|
+
let parsed
|
|
51
|
+
try {
|
|
52
|
+
parsed = parseArgsFn({ args: argv, options, allowPositionals: false })
|
|
53
|
+
} catch (err) {
|
|
54
|
+
writeStderr(`Error: ${err.message}\n`)
|
|
55
|
+
writeStderr('Run with --help for usage information.\n')
|
|
56
|
+
return 1
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const { values } = parsed
|
|
60
|
+
|
|
61
|
+
if (values.help) {
|
|
62
|
+
writeStdout(HELP_TEXT)
|
|
63
|
+
return 0
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const mode = values.mode || 'local'
|
|
67
|
+
|
|
68
|
+
if (mode === 'local') {
|
|
69
|
+
const projectRoot = resolvePath(values['project-root'] || '.')
|
|
70
|
+
|
|
71
|
+
if (!existsSyncFn(projectRoot)) {
|
|
72
|
+
writeStderr(`Error: Project root does not exist: ${projectRoot}\n`)
|
|
73
|
+
return 1
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const claudeMdPath = values['claude-md'] || null
|
|
77
|
+
const verbose = values.verbose || false
|
|
78
|
+
|
|
79
|
+
const { startLocal } = await importServer()
|
|
80
|
+
await startLocal(projectRoot, { claudeMdPath, verbose, tier: 'pro' })
|
|
81
|
+
return 0
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (mode === 'remote') {
|
|
85
|
+
const port = parseInt(values.port || '3000', 10)
|
|
86
|
+
const verbose = values.verbose || false
|
|
87
|
+
|
|
88
|
+
const { startRemote } = await importServer()
|
|
89
|
+
try {
|
|
90
|
+
await startRemote({ port, verbose })
|
|
91
|
+
} catch (err) {
|
|
92
|
+
writeStderr(`Error: ${err.message}\n`)
|
|
93
|
+
return 1
|
|
94
|
+
}
|
|
95
|
+
return 0
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
writeStderr(`Error: Unknown mode "${mode}". Use "local" or "remote".\n`)
|
|
99
|
+
return 1
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function shouldRunAsCli(
|
|
103
|
+
argv1 = process.argv[1],
|
|
104
|
+
metaUrl = import.meta.url,
|
|
105
|
+
) {
|
|
106
|
+
return Boolean(argv1) && metaUrl === pathToFileURL(argv1).href
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export async function runCliIfInvoked(deps = {}) {
|
|
110
|
+
const argv1 = deps.argv1 ?? process.argv[1]
|
|
111
|
+
const metaUrl = deps.metaUrl ?? import.meta.url
|
|
112
|
+
const mainFn = deps.mainFn || main
|
|
113
|
+
const exitFn = deps.exitFn || ((code) => process.exit(code))
|
|
114
|
+
|
|
115
|
+
if (!shouldRunAsCli(argv1, metaUrl)) {
|
|
116
|
+
return false
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const exitCode = await mainFn()
|
|
120
|
+
if (exitCode !== 0) {
|
|
121
|
+
exitFn(exitCode)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return true
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (await runCliIfInvoked()) {
|
|
128
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reinteractive/rails-insight",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Rails-aware codebase indexer — MCP server for AI agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"railsinsight": "bin/railsinsight.js"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/reinteractive/rails-insight.git"
|
|
12
|
+
},
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/reinteractive/rails-insight#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/reinteractive/rails-insight/issues"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"rails",
|
|
22
|
+
"mcp",
|
|
23
|
+
"model-context-protocol",
|
|
24
|
+
"ai",
|
|
25
|
+
"indexer",
|
|
26
|
+
"code-analysis",
|
|
27
|
+
"ruby",
|
|
28
|
+
"ruby-on-rails"
|
|
29
|
+
],
|
|
30
|
+
"license": "ISC",
|
|
31
|
+
"files": [
|
|
32
|
+
"bin/",
|
|
33
|
+
"src/",
|
|
34
|
+
"README.md"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"start": "node bin/railsinsight.js",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:watch": "vitest",
|
|
40
|
+
"test:patterns": "vitest run test/patterns/",
|
|
41
|
+
"test:extractors": "vitest run test/extractors/",
|
|
42
|
+
"test:core": "vitest run test/core/",
|
|
43
|
+
"test:contracts": "vitest run test/contracts/",
|
|
44
|
+
"test:golden": "vitest run test/golden/",
|
|
45
|
+
"test:edge": "vitest run test/edge-cases/",
|
|
46
|
+
"test:perf": "vitest run test/performance/",
|
|
47
|
+
"test:cross-version": "vitest run test/cross-version/",
|
|
48
|
+
"test:mcp": "vitest run test/mcp/",
|
|
49
|
+
"test:coverage": "vitest run --coverage"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
53
|
+
"zod": "^3.25.0"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
57
|
+
"vitest": "^3.0.0"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=18.0.0"
|
|
61
|
+
}
|
|
62
|
+
}
|