rails-markup 1.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 +7 -0
- data/LICENSE +21 -0
- data/README.md +304 -0
- data/app/assets/javascripts/rails_markup/toolbar.js +2225 -0
- data/app/controllers/rails_markup/annotations_controller.rb +244 -0
- data/app/controllers/rails_markup/application_controller.rb +7 -0
- data/app/controllers/rails_markup/dashboard_controller.rb +230 -0
- data/app/controllers/rails_markup/external/annotations_controller.rb +68 -0
- data/app/models/rails_markup/annotation.rb +176 -0
- data/app/views/layouts/rails_markup/application.html.erb +158 -0
- data/app/views/rails_markup/dashboard/_annotation_card.html.erb +25 -0
- data/app/views/rails_markup/dashboard/_annotation_list.html.erb +57 -0
- data/app/views/rails_markup/dashboard/_annotation_page.html.erb +13 -0
- data/app/views/rails_markup/dashboard/_filters.html.erb +75 -0
- data/app/views/rails_markup/dashboard/_stats.html.erb +22 -0
- data/app/views/rails_markup/dashboard/_styles.html.erb +115 -0
- data/app/views/rails_markup/dashboard/board.html.erb +135 -0
- data/app/views/rails_markup/dashboard/index.html.erb +38 -0
- data/app/views/rails_markup/dashboard/show.html.erb +129 -0
- data/app/views/rails_markup/shared/_toolbar.html.erb +28 -0
- data/bin/rails-markup +5 -0
- data/config/routes.rb +45 -0
- data/db/migrate/20260720000000_add_client_uuid_to_rails_markup_annotations.rb +13 -0
- data/db/migrate/20260721000000_backfill_rails_markup_client_uuids.rb +17 -0
- data/lib/generators/rails_markup/install/templates/auth_controller.rb.erb +17 -0
- data/lib/generators/rails_markup/install/templates/bin_markup.erb +5 -0
- data/lib/generators/rails_markup/install/templates/create_rails_markup_annotations.rb.erb +27 -0
- data/lib/generators/rails_markup/install/templates/initializer.rb.erb +54 -0
- data/lib/generators/rails_markup/install_generator.rb +167 -0
- data/lib/generators/rails_markup/uninstall_generator.rb +110 -0
- data/lib/rails_markup/cli/base.rb +8 -0
- data/lib/rails_markup/cli/initializer_writer.rb +54 -0
- data/lib/rails_markup/cli/setup_wizard.rb +229 -0
- data/lib/rails_markup/cli.rb +831 -0
- data/lib/rails_markup/client_uuid_maintenance.rb +174 -0
- data/lib/rails_markup/configuration.rb +160 -0
- data/lib/rails_markup/engine.rb +18 -0
- data/lib/rails_markup/http_server.rb +226 -0
- data/lib/rails_markup/http_store_proxy.rb +122 -0
- data/lib/rails_markup/mcp_config.rb +258 -0
- data/lib/rails_markup/mcp_server.rb +639 -0
- data/lib/rails_markup/server.rb +73 -0
- data/lib/rails_markup/store.rb +219 -0
- data/lib/rails_markup/version.rb +5 -0
- data/lib/rails_markup.rb +11 -0
- data/lib/tasks/rails_markup_client_uuids.rake +19 -0
- metadata +198 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: ba51cbb26a37ce1d218f565367f1f15010b3cbe2b884dc2c19000b3b2607b50d
|
|
4
|
+
data.tar.gz: efca7d5c37141a1a45b01d6b47e84388f6acc50c514626d53adaea6bb78b71a9
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: e47f3a1181804194ceaa5c1787b720df7df1a5eb9e3bdecf3f9cf3d3e622d79fb11f7aa4d1d5b0c75b971f70e02f2e8910bb75ae4711e1bf096ad1cf49241474
|
|
7
|
+
data.tar.gz: e65d97dd4e0730aaa0023aaf8cc8405b770af6e85f566a47aeab5c39ef0dd38a24d143586ef2064bfc05dd330a4df504c73901d7fdc2cb93ce6cab5ba585cbbd
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 InventList
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# Rails Markup
|
|
2
|
+
|
|
3
|
+
Point-and-click annotation tool for Rails apps. Click any element, describe what needs to change, and your AI agent reads and acts on your feedback via MCP.
|
|
4
|
+
|
|
5
|
+
**v1.0** — Author attribution, export, search, screenshots with drawing tools, kanban board, notification hooks.
|
|
6
|
+
|
|
7
|
+
## How it works
|
|
8
|
+
|
|
9
|
+
1. **Install the gem** — adds migration, toolbar, auth controller, and routes
|
|
10
|
+
2. **Open your app** — the annotation toolbar appears as a floating button
|
|
11
|
+
3. **Click any element** — hover to highlight, click to annotate with screenshots
|
|
12
|
+
4. **Draw on screenshots** — arrows, rectangles, highlights on captured elements
|
|
13
|
+
5. **Agent reads it** — AI calls `rails_markup_read` via MCP
|
|
14
|
+
6. **Agent fixes it** — resolves the annotation and moves on
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
# Gemfile
|
|
20
|
+
gem "rails-markup", github: "inventlist/rails-markup", require: "rails_markup"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
bundle install
|
|
25
|
+
rails generate rails_markup:install
|
|
26
|
+
rails db:migrate
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
When upgrading an existing installation, copy and run new engine migrations:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
bin/rails railties:install:migrations FROM=rails_markup
|
|
33
|
+
bin/rails db:migrate
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Rails Markup 1.2 rolling UUID upgrade
|
|
37
|
+
|
|
38
|
+
The 1.2 upgrade migration adds, repairs, and uniquely indexes `client_uuid`, but
|
|
39
|
+
deliberately leaves the column nullable while old application instances may
|
|
40
|
+
still be serving traffic. Fresh installs create it as `NOT NULL` immediately.
|
|
41
|
+
|
|
42
|
+
For a rolling upgrade:
|
|
43
|
+
|
|
44
|
+
1. Run the copied migrations and deploy 1.2 to every application instance.
|
|
45
|
+
2. Wait until all old pre-1.2 instances are drained and have stopped.
|
|
46
|
+
3. Repair any rows written during the mixed-version window, then verify:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
bin/rails rails_markup:client_uuids:repair
|
|
50
|
+
bin/rails rails_markup:client_uuids:verify
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Both commands are safe to repeat. A pull containing any lingering blank or
|
|
54
|
+
noncanonical identity returns `503` without mutating data. Do not add a
|
|
55
|
+
`NOT NULL` constraint until verification stays green after old instances are
|
|
56
|
+
drained; that explicit contract migration belongs in a later release.
|
|
57
|
+
|
|
58
|
+
The generator creates:
|
|
59
|
+
|
|
60
|
+
| File | Purpose |
|
|
61
|
+
|------|---------|
|
|
62
|
+
| `db/migrate/*_create_rails_markup_annotations.rb` | Annotations table |
|
|
63
|
+
| `config/initializers/rails_markup.rb` | Configuration |
|
|
64
|
+
| `app/controllers/rails_markup_auth_controller.rb` | Auth controller |
|
|
65
|
+
| `bin/markup` | CLI wrapper |
|
|
66
|
+
| Route mount | Engine at `/admin/annotations` |
|
|
67
|
+
| Toolbar injection | `<%= render "rails_markup/shared/toolbar" %>` in your layout |
|
|
68
|
+
|
|
69
|
+
### Generator options
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
rails generate rails_markup:install \
|
|
73
|
+
--mount-path=/admin/annotations \
|
|
74
|
+
--base-controller=Admin::BaseController \
|
|
75
|
+
--layout=application
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Authentication and browser synchronization
|
|
79
|
+
|
|
80
|
+
The generated `RailsMarkupAuthController` protects both the mounted dashboard
|
|
81
|
+
and the toolbar API. It denies access unless `current_user.admin?` is true;
|
|
82
|
+
customize `authorize_rails_markup!` if your host uses another authorization
|
|
83
|
+
policy. The configured base controller must actually enforce authorization.
|
|
84
|
+
Choosing a public controller makes both interfaces public.
|
|
85
|
+
|
|
86
|
+
The toolbar uses the same host authentication boundary as the dashboard and
|
|
87
|
+
sends normal Rails CSRF tokens on every mutation. Keep `csrf_meta_tags` in the
|
|
88
|
+
host layout. Rails is authoritative; localStorage is an offline cache and a
|
|
89
|
+
durable desired-state outbox, keyed by a client UUID.
|
|
90
|
+
|
|
91
|
+
During reconciliation, browser-owned content, intent, severity, selection,
|
|
92
|
+
target, permitted metadata, and an explicitly dirty status remain local until a
|
|
93
|
+
successful UUID PUT. Server-owned thread, author/user identity, and timestamps
|
|
94
|
+
always win. A complete exact-page pull may remove a synced local record absent
|
|
95
|
+
from Rails, but never removes pending upserts or delete tombstones.
|
|
96
|
+
|
|
97
|
+
### Uninstall
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
rails generate rails_markup:uninstall
|
|
101
|
+
# Add --remove-migration to also delete the migration file
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Configuration
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
# config/initializers/rails_markup.rb
|
|
108
|
+
RailsMarkup.configure do |config|
|
|
109
|
+
# Auth controller for dashboard and toolbar API; it must authorize access.
|
|
110
|
+
config.base_controller_class = "RailsMarkupAuthController"
|
|
111
|
+
|
|
112
|
+
# External API token (for MCP production tools)
|
|
113
|
+
config.api_token = Rails.application.credentials.dig(:rails_markup, :api_token)
|
|
114
|
+
|
|
115
|
+
# Author display name from current_user
|
|
116
|
+
config.author_name_method = :name
|
|
117
|
+
# Or use a Proc:
|
|
118
|
+
# config.author_name_method = ->(user) { "#{user.first_name} #{user.last_name}" }
|
|
119
|
+
|
|
120
|
+
# Callback fired after each annotation is created
|
|
121
|
+
config.on_create_callback = ->(annotation) {
|
|
122
|
+
SlackNotifier.notify("Feedback on #{annotation.page_url}: #{annotation.content}")
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# Toolbar accent color: indigo, amber, blue, emerald, rose
|
|
126
|
+
config.toolbar_accent = "indigo"
|
|
127
|
+
|
|
128
|
+
# Show or hide the annotation toolbar and FAB (default: true)
|
|
129
|
+
config.toolbar_enabled = true
|
|
130
|
+
|
|
131
|
+
# FAB corner: bl, br, tl, tr; size: slim, compact, default
|
|
132
|
+
config.toolbar_position = "bl"
|
|
133
|
+
config.toolbar_size = "default"
|
|
134
|
+
|
|
135
|
+
# Element screenshots (default: true)
|
|
136
|
+
config.enable_screenshots = true
|
|
137
|
+
|
|
138
|
+
# Dashboard pagination (default: 25)
|
|
139
|
+
config.per_page = 25
|
|
140
|
+
|
|
141
|
+
# "Back to app" link
|
|
142
|
+
config.return_url = "/admin"
|
|
143
|
+
end
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Dashboard
|
|
147
|
+
|
|
148
|
+
Visit `/admin/annotations` for the full dashboard:
|
|
149
|
+
|
|
150
|
+
- **List view** — status filters, search, author filter, load-more pagination
|
|
151
|
+
- **Board view** — kanban with drag-and-drop status transitions
|
|
152
|
+
- **Export** — CSV and JSON downloads (respects current filters)
|
|
153
|
+
- **Detail panel** — full content, metadata, screenshots, thread
|
|
154
|
+
- **Bulk actions** — dismiss all pending/acknowledged
|
|
155
|
+
|
|
156
|
+
### Search & Filters
|
|
157
|
+
|
|
158
|
+
- **Text search** — searches annotation content and selected text
|
|
159
|
+
- **Author filter** — filter by who created the annotation
|
|
160
|
+
- **Page URL filter** — filter by annotated page
|
|
161
|
+
- **Status pills** — pending, acknowledged, resolved, dismissed
|
|
162
|
+
|
|
163
|
+
## Screenshots & Drawing
|
|
164
|
+
|
|
165
|
+
When you click an element, the toolbar captures a screenshot using SVG foreignObject. Before submitting, you can draw on it:
|
|
166
|
+
|
|
167
|
+
- **Arrow** — click and drag to draw red arrows
|
|
168
|
+
- **Rectangle** — click and drag for red outline boxes
|
|
169
|
+
- **Highlight** — freehand semi-transparent yellow strokes
|
|
170
|
+
- **Undo** — remove the last drawing operation
|
|
171
|
+
|
|
172
|
+
Screenshots are stored as base64 in annotation metadata and displayed in the dashboard detail view.
|
|
173
|
+
|
|
174
|
+
## CLI
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
# Setup
|
|
178
|
+
bin/markup init # Interactive setup wizard (TUI)
|
|
179
|
+
bin/markup configure # Set .mcp.json env vars
|
|
180
|
+
bin/markup status # Show config (tokens masked)
|
|
181
|
+
bin/markup setup-production --url=URL # Generate token + configure
|
|
182
|
+
|
|
183
|
+
# Server
|
|
184
|
+
bin/markup server # HTTP + MCP server
|
|
185
|
+
bin/markup mcp # MCP-only server (stdio)
|
|
186
|
+
|
|
187
|
+
# Annotations (match MCP tool verbs)
|
|
188
|
+
bin/markup pending # Fetch pending from dev
|
|
189
|
+
bin/markup pending --production # Fetch from production
|
|
190
|
+
bin/markup resolve 42 --summary "..." # Resolve an annotation
|
|
191
|
+
bin/markup dismiss 42 --reason "..." # Dismiss an annotation
|
|
192
|
+
bin/markup reply 42 "message" # Reply to an annotation
|
|
193
|
+
bin/markup acknowledge 42 # Mark as acknowledged
|
|
194
|
+
bin/markup watch # Poll for new annotations
|
|
195
|
+
bin/markup watch --production # Watch production
|
|
196
|
+
|
|
197
|
+
# Info
|
|
198
|
+
bin/markup sessions # Session info (MCP only)
|
|
199
|
+
bin/markup session ID # Session detail (MCP only)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Setup Wizard
|
|
203
|
+
|
|
204
|
+
Run `bin/markup init` for an interactive setup that walks you through:
|
|
205
|
+
|
|
206
|
+
1. Toolbar accent color (indigo, amber, blue, emerald, rose)
|
|
207
|
+
2. Toolbar position (bottom-left, bottom-right, top-left, top-right)
|
|
208
|
+
3. Toolbar size (slim, compact, default)
|
|
209
|
+
4. Screenshot capture (on/off)
|
|
210
|
+
5. Production URL (optional)
|
|
211
|
+
|
|
212
|
+
Writes `config/initializers/rails_markup.rb` and updates `.mcp.json` automatically.
|
|
213
|
+
|
|
214
|
+
## MCP Setup
|
|
215
|
+
|
|
216
|
+
Add to `.mcp.json`:
|
|
217
|
+
|
|
218
|
+
```json
|
|
219
|
+
{
|
|
220
|
+
"mcpServers": {
|
|
221
|
+
"rails-markup": {
|
|
222
|
+
"type": "stdio",
|
|
223
|
+
"command": "ruby",
|
|
224
|
+
"args": ["bin/markup", "mcp"],
|
|
225
|
+
"env": {
|
|
226
|
+
"RAILS_MARKUP_DEV_URL": "http://localhost:3000",
|
|
227
|
+
"RAILS_MARKUP_PROD_URL": "https://yourapp.com",
|
|
228
|
+
"RAILS_MARKUP_PROD_TOKEN": "your-prod-api-token"
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### MCP tools (five canonical thin-enum tools)
|
|
236
|
+
|
|
237
|
+
The MCP server advertises exactly five tools. Their schemas reject unknown
|
|
238
|
+
arguments and use small enums instead of multiplying environment-specific tool
|
|
239
|
+
names:
|
|
240
|
+
|
|
241
|
+
| Tool | Contract |
|
|
242
|
+
|------|----------|
|
|
243
|
+
| `rails_markup_read` | Read `pending`, `sessions`, `session`, or `annotation`; never acknowledges |
|
|
244
|
+
| `rails_markup_watch` | Watch development annotations with bounded timeout/window |
|
|
245
|
+
| `rails_markup_transition` | `acknowledge` or `resolve` an annotation |
|
|
246
|
+
| `rails_markup_reply` | Add an agent reply |
|
|
247
|
+
| `rails_markup_dismiss` | Destructively dismiss with a reason |
|
|
248
|
+
|
|
249
|
+
`environment` is `development` or `production` where supported. Production URL
|
|
250
|
+
and bearer credentials come only from trusted process configuration.
|
|
251
|
+
Caller-supplied URL and token overrides are rejected and are never forwarded.
|
|
252
|
+
|
|
253
|
+
### Legacy MCP compatibility
|
|
254
|
+
|
|
255
|
+
Legacy names remain hidden but callable as explicit, warning-emitting adapters
|
|
256
|
+
during the 1.2/1.3 compatibility window. They never restore caller-controlled
|
|
257
|
+
credentials or mutating reads. They will be removed after 1.3.0; migrate clients
|
|
258
|
+
to the five canonical tools above.
|
|
259
|
+
|
|
260
|
+
## Annotation Data
|
|
261
|
+
|
|
262
|
+
Each annotation includes:
|
|
263
|
+
|
|
264
|
+
- **Content** — what needs to change (max 5000 chars)
|
|
265
|
+
- **CSS selector** — `div#hero.max-w-xl`
|
|
266
|
+
- **CSS path** — `body > main > div:nth-of-type(2) > div#hero`
|
|
267
|
+
- **Bounding box** — `{ top, left, width, height }`
|
|
268
|
+
- **Nearby text** — first 80 chars of element text
|
|
269
|
+
- **Selected text** — highlighted text before clicking
|
|
270
|
+
- **Screenshot** — element capture with optional drawings
|
|
271
|
+
- **Author** — who created it (via `author_name_method`)
|
|
272
|
+
- **Intent** — `fix`, `change`, `question`, or `approve`
|
|
273
|
+
- **Severity** — `suggestion`, `important`, or `blocking`
|
|
274
|
+
|
|
275
|
+
## Architecture
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
Browser Toolbar AI Agent (Claude Code, Cursor)
|
|
279
|
+
| |
|
|
280
|
+
| Authenticated same-origin API | MCP (stdio JSON-RPC)
|
|
281
|
+
| (pull + UUID PUT/DELETE, CSRF) | or CLI (bin/markup pending)
|
|
282
|
+
v v
|
|
283
|
+
+----------------------------------------------------------+
|
|
284
|
+
| Rails Engine |
|
|
285
|
+
| |
|
|
286
|
+
| Toolbar → Annotations → Dashboard |
|
|
287
|
+
| (vanilla JS) (ActiveRecord) (list + board views) |
|
|
288
|
+
| ↑ |
|
|
289
|
+
| External API (/external/*) |
|
|
290
|
+
| (token-authenticated, used by MCP) |
|
|
291
|
+
+----------------------------------------------------------+
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Development
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
git clone https://github.com/inventlist/rails-markup
|
|
298
|
+
cd rails-markup && bundle install
|
|
299
|
+
bundle exec ruby -Ilib:test test/**/*_test.rb
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## License
|
|
303
|
+
|
|
304
|
+
MIT. See [LICENSE](LICENSE).
|