source_monitor 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b8348a9154458260c8b6a3c3dfdeea65e8327b9d7a48dd6c1a2fbe36f9f1bf46
4
- data.tar.gz: 2d56c477bc1191f4f505645f9f9f23fceaa1f15d1fd065e5032ac2d40ae3c0d3
3
+ metadata.gz: 24dc578d91173b255c4d1a4ecc7d85542c5c2a86daabac9ee779b73c4f012ed5
4
+ data.tar.gz: 43f2ae2005109c50a5c3298c315a48092926411e02a8a4715459e39304324e14
5
5
  SHA512:
6
- metadata.gz: 5f875810a4a5e53aae8ec0609e0ab86a3a97ba8661826de6dcd8cf3abd3091f3e4838d8c301ed0f962da0c5849123f8a1fa7c2614e5341126753a8556a0d6fce
7
- data.tar.gz: 50a7007476a9b989af9bfe989bc758a9febbc80478c541995044e1a6fd55fe54736520f643ca00845de57a4d5fc5ccfe1d83dd7994affff7530a3cd692f6fb96
6
+ metadata.gz: 640830590b4e1638b0fd2e90c337f49f41c788948abd7a2552338a15e80b13560da320d449ec55fad12a6a9724916af2e1a0942129ca396e9c11f0ddb3abcc89
7
+ data.tar.gz: 5dae4fbfe5864a33fd2895a275f2511d014e5a94ccf49a19bc1f4d0c284bd9045a561c003e945fec3acf9565b116f868616c45566310857675f3b02d3768f0e8
@@ -244,3 +244,51 @@
244
244
  "title": "",
245
245
  "message": "Claude Code needs your approval for the plan"
246
246
  }
247
+ {
248
+ "timestamp": "2026-02-11T05:06:47Z",
249
+ "type": "idle_prompt",
250
+ "title": "",
251
+ "message": "Claude is waiting for your input"
252
+ }
253
+ {
254
+ "timestamp": "2026-02-11T05:08:54Z",
255
+ "type": "idle_prompt",
256
+ "title": "",
257
+ "message": "Claude is waiting for your input"
258
+ }
259
+ {
260
+ "timestamp": "2026-02-11T05:11:34Z",
261
+ "type": "idle_prompt",
262
+ "title": "",
263
+ "message": "Claude is waiting for your input"
264
+ }
265
+ {
266
+ "timestamp": "2026-02-11T05:14:10Z",
267
+ "type": "idle_prompt",
268
+ "title": "",
269
+ "message": "Claude is waiting for your input"
270
+ }
271
+ {
272
+ "timestamp": "2026-02-11T05:15:43Z",
273
+ "type": "idle_prompt",
274
+ "title": "",
275
+ "message": "Claude is waiting for your input"
276
+ }
277
+ {
278
+ "timestamp": "2026-02-11T05:20:49Z",
279
+ "type": "idle_prompt",
280
+ "title": "",
281
+ "message": "Claude is waiting for your input"
282
+ }
283
+ {
284
+ "timestamp": "2026-02-11T05:24:55Z",
285
+ "type": "idle_prompt",
286
+ "title": "",
287
+ "message": "Claude is waiting for your input"
288
+ }
289
+ {
290
+ "timestamp": "2026-02-11T05:35:24Z",
291
+ "type": "idle_prompt",
292
+ "title": "",
293
+ "message": "Claude is waiting for your input"
294
+ }
@@ -990,3 +990,387 @@
990
990
  "other": 89
991
991
  }
992
992
  }
993
+ {
994
+ "timestamp": "2026-02-11T05:05:47Z",
995
+ "duration_ms": 0,
996
+ "cost_usd": 0,
997
+ "tokens_in": 0,
998
+ "tokens_out": 0,
999
+ "model": "unknown",
1000
+ "branch": "chore/dependency-updates"
1001
+ }
1002
+ {
1003
+ "timestamp": "2026-02-11T05:05:47Z",
1004
+ "type": "cost_summary",
1005
+ "costs": {
1006
+ "other": 380
1007
+ }
1008
+ }
1009
+ {
1010
+ "timestamp": "2026-02-11T05:07:54Z",
1011
+ "duration_ms": 0,
1012
+ "cost_usd": 0,
1013
+ "tokens_in": 0,
1014
+ "tokens_out": 0,
1015
+ "model": "unknown",
1016
+ "branch": "chore/dependency-updates"
1017
+ }
1018
+ {
1019
+ "timestamp": "2026-02-11T05:07:54Z",
1020
+ "type": "cost_summary",
1021
+ "costs": {
1022
+ "other": 51
1023
+ }
1024
+ }
1025
+ {
1026
+ "timestamp": "2026-02-11T05:10:33Z",
1027
+ "duration_ms": 0,
1028
+ "cost_usd": 0,
1029
+ "tokens_in": 0,
1030
+ "tokens_out": 0,
1031
+ "model": "unknown",
1032
+ "branch": "chore/dependency-updates"
1033
+ }
1034
+ {
1035
+ "timestamp": "2026-02-11T05:10:33Z",
1036
+ "type": "cost_summary",
1037
+ "costs": {
1038
+ "other": 59
1039
+ }
1040
+ }
1041
+ {
1042
+ "timestamp": "2026-02-11T05:13:09Z",
1043
+ "duration_ms": 0,
1044
+ "cost_usd": 0,
1045
+ "tokens_in": 0,
1046
+ "tokens_out": 0,
1047
+ "model": "unknown",
1048
+ "branch": "chore/dependency-updates"
1049
+ }
1050
+ {
1051
+ "timestamp": "2026-02-11T05:13:09Z",
1052
+ "type": "cost_summary",
1053
+ "costs": {
1054
+ "other": 25
1055
+ }
1056
+ }
1057
+ {
1058
+ "timestamp": "2026-02-11T05:14:42Z",
1059
+ "duration_ms": 0,
1060
+ "cost_usd": 0,
1061
+ "tokens_in": 0,
1062
+ "tokens_out": 0,
1063
+ "model": "unknown",
1064
+ "branch": "chore/dependency-updates"
1065
+ }
1066
+ {
1067
+ "timestamp": "2026-02-11T05:14:42Z",
1068
+ "type": "cost_summary",
1069
+ "costs": {
1070
+ "other": 17
1071
+ }
1072
+ }
1073
+ {
1074
+ "timestamp": "2026-02-11T05:19:49Z",
1075
+ "duration_ms": 0,
1076
+ "cost_usd": 0,
1077
+ "tokens_in": 0,
1078
+ "tokens_out": 0,
1079
+ "model": "unknown",
1080
+ "branch": "chore/dependency-updates"
1081
+ }
1082
+ {
1083
+ "timestamp": "2026-02-11T05:19:49Z",
1084
+ "type": "cost_summary",
1085
+ "costs": {
1086
+ "other": 23
1087
+ }
1088
+ }
1089
+ {
1090
+ "timestamp": "2026-02-11T05:21:52Z",
1091
+ "duration_ms": 0,
1092
+ "cost_usd": 0,
1093
+ "tokens_in": 0,
1094
+ "tokens_out": 0,
1095
+ "model": "unknown",
1096
+ "branch": "chore/dependency-updates"
1097
+ }
1098
+ {
1099
+ "timestamp": "2026-02-11T05:21:52Z",
1100
+ "type": "cost_summary",
1101
+ "costs": {
1102
+ "other": 6
1103
+ }
1104
+ }
1105
+ {
1106
+ "timestamp": "2026-02-11T05:22:48Z",
1107
+ "duration_ms": 0,
1108
+ "cost_usd": 0,
1109
+ "tokens_in": 0,
1110
+ "tokens_out": 0,
1111
+ "model": "unknown",
1112
+ "branch": "main"
1113
+ }
1114
+ {
1115
+ "timestamp": "2026-02-11T05:22:48Z",
1116
+ "type": "cost_summary",
1117
+ "costs": {
1118
+ "other": 32
1119
+ }
1120
+ }
1121
+ {
1122
+ "timestamp": "2026-02-11T05:23:55Z",
1123
+ "duration_ms": 0,
1124
+ "cost_usd": 0,
1125
+ "tokens_in": 0,
1126
+ "tokens_out": 0,
1127
+ "model": "unknown",
1128
+ "branch": "main"
1129
+ }
1130
+ {
1131
+ "timestamp": "2026-02-11T05:23:55Z",
1132
+ "type": "cost_summary",
1133
+ "costs": {
1134
+ "other": 52
1135
+ }
1136
+ }
1137
+ {
1138
+ "timestamp": "2026-02-11T05:28:15Z",
1139
+ "duration_ms": 0,
1140
+ "cost_usd": 0,
1141
+ "tokens_in": 0,
1142
+ "tokens_out": 0,
1143
+ "model": "unknown",
1144
+ "branch": "main"
1145
+ }
1146
+ {
1147
+ "timestamp": "2026-02-11T05:28:15Z",
1148
+ "type": "cost_summary",
1149
+ "costs": {
1150
+ "other": 164
1151
+ }
1152
+ }
1153
+ {
1154
+ "timestamp": "2026-02-11T05:29:11Z",
1155
+ "duration_ms": 0,
1156
+ "cost_usd": 0,
1157
+ "tokens_in": 0,
1158
+ "tokens_out": 0,
1159
+ "model": "unknown",
1160
+ "branch": "main"
1161
+ }
1162
+ {
1163
+ "timestamp": "2026-02-11T05:29:11Z",
1164
+ "type": "cost_summary",
1165
+ "costs": {
1166
+ "other": 147
1167
+ }
1168
+ }
1169
+ {
1170
+ "timestamp": "2026-02-11T05:29:14Z",
1171
+ "duration_ms": 0,
1172
+ "cost_usd": 0,
1173
+ "tokens_in": 0,
1174
+ "tokens_out": 0,
1175
+ "model": "unknown",
1176
+ "branch": "main"
1177
+ }
1178
+ {
1179
+ "timestamp": "2026-02-11T05:29:14Z",
1180
+ "type": "cost_summary",
1181
+ "costs": {
1182
+ "other": 13
1183
+ }
1184
+ }
1185
+ {
1186
+ "timestamp": "2026-02-11T05:29:17Z",
1187
+ "duration_ms": 0,
1188
+ "cost_usd": 0,
1189
+ "tokens_in": 0,
1190
+ "tokens_out": 0,
1191
+ "model": "unknown",
1192
+ "branch": "main"
1193
+ }
1194
+ {
1195
+ "timestamp": "2026-02-11T05:29:17Z",
1196
+ "type": "cost_summary",
1197
+ "costs": {
1198
+ "other": 5
1199
+ }
1200
+ }
1201
+ {
1202
+ "timestamp": "2026-02-11T05:29:20Z",
1203
+ "duration_ms": 0,
1204
+ "cost_usd": 0,
1205
+ "tokens_in": 0,
1206
+ "tokens_out": 0,
1207
+ "model": "unknown",
1208
+ "branch": "main"
1209
+ }
1210
+ {
1211
+ "timestamp": "2026-02-11T05:29:20Z",
1212
+ "type": "cost_summary",
1213
+ "costs": {
1214
+ "other": 13
1215
+ }
1216
+ }
1217
+ {
1218
+ "timestamp": "2026-02-11T05:29:23Z",
1219
+ "duration_ms": 0,
1220
+ "cost_usd": 0,
1221
+ "tokens_in": 0,
1222
+ "tokens_out": 0,
1223
+ "model": "unknown",
1224
+ "branch": "main"
1225
+ }
1226
+ {
1227
+ "timestamp": "2026-02-11T05:29:23Z",
1228
+ "type": "cost_summary",
1229
+ "costs": {
1230
+ "other": 25
1231
+ }
1232
+ }
1233
+ {
1234
+ "timestamp": "2026-02-11T05:29:26Z",
1235
+ "duration_ms": 0,
1236
+ "cost_usd": 0,
1237
+ "tokens_in": 0,
1238
+ "tokens_out": 0,
1239
+ "model": "unknown",
1240
+ "branch": "main"
1241
+ }
1242
+ {
1243
+ "timestamp": "2026-02-11T05:29:26Z",
1244
+ "type": "cost_summary",
1245
+ "costs": {
1246
+ "other": 13
1247
+ }
1248
+ }
1249
+ {
1250
+ "timestamp": "2026-02-11T05:29:29Z",
1251
+ "duration_ms": 0,
1252
+ "cost_usd": 0,
1253
+ "tokens_in": 0,
1254
+ "tokens_out": 0,
1255
+ "model": "unknown",
1256
+ "branch": "main"
1257
+ }
1258
+ {
1259
+ "timestamp": "2026-02-11T05:29:29Z",
1260
+ "type": "cost_summary",
1261
+ "costs": {
1262
+ "other": 14
1263
+ }
1264
+ }
1265
+ {
1266
+ "timestamp": "2026-02-11T05:29:32Z",
1267
+ "duration_ms": 0,
1268
+ "cost_usd": 0,
1269
+ "tokens_in": 0,
1270
+ "tokens_out": 0,
1271
+ "model": "unknown",
1272
+ "branch": "main"
1273
+ }
1274
+ {
1275
+ "timestamp": "2026-02-11T05:29:32Z",
1276
+ "type": "cost_summary",
1277
+ "costs": {
1278
+ "other": 13
1279
+ }
1280
+ }
1281
+ {
1282
+ "timestamp": "2026-02-11T05:30:26Z",
1283
+ "duration_ms": 0,
1284
+ "cost_usd": 0,
1285
+ "tokens_in": 0,
1286
+ "tokens_out": 0,
1287
+ "model": "unknown",
1288
+ "branch": "main"
1289
+ }
1290
+ {
1291
+ "timestamp": "2026-02-11T05:30:26Z",
1292
+ "type": "cost_summary",
1293
+ "costs": {
1294
+ "other": 74
1295
+ }
1296
+ }
1297
+ {
1298
+ "timestamp": "2026-02-11T05:30:33Z",
1299
+ "duration_ms": 0,
1300
+ "cost_usd": 0,
1301
+ "tokens_in": 0,
1302
+ "tokens_out": 0,
1303
+ "model": "unknown",
1304
+ "branch": "main"
1305
+ }
1306
+ {
1307
+ "timestamp": "2026-02-11T05:30:33Z",
1308
+ "type": "cost_summary",
1309
+ "costs": {
1310
+ "other": 29
1311
+ }
1312
+ }
1313
+ {
1314
+ "timestamp": "2026-02-11T05:32:32Z",
1315
+ "duration_ms": 0,
1316
+ "cost_usd": 0,
1317
+ "tokens_in": 0,
1318
+ "tokens_out": 0,
1319
+ "model": "unknown",
1320
+ "branch": "docs/v0.3.2-documentation-updates"
1321
+ }
1322
+ {
1323
+ "timestamp": "2026-02-11T05:32:32Z",
1324
+ "type": "cost_summary",
1325
+ "costs": {
1326
+ "other": 66
1327
+ }
1328
+ }
1329
+ {
1330
+ "timestamp": "2026-02-11T05:34:23Z",
1331
+ "duration_ms": 0,
1332
+ "cost_usd": 0,
1333
+ "tokens_in": 0,
1334
+ "tokens_out": 0,
1335
+ "model": "unknown",
1336
+ "branch": "docs/v0.3.2-documentation-updates"
1337
+ }
1338
+ {
1339
+ "timestamp": "2026-02-11T05:34:23Z",
1340
+ "type": "cost_summary",
1341
+ "costs": {
1342
+ "other": 34
1343
+ }
1344
+ }
1345
+ {
1346
+ "timestamp": "2026-02-11T05:44:50Z",
1347
+ "duration_ms": 0,
1348
+ "cost_usd": 0,
1349
+ "tokens_in": 0,
1350
+ "tokens_out": 0,
1351
+ "model": "unknown",
1352
+ "branch": "docs/v0.3.2-documentation-updates"
1353
+ }
1354
+ {
1355
+ "timestamp": "2026-02-11T05:44:50Z",
1356
+ "type": "cost_summary",
1357
+ "costs": {
1358
+ "other": 69
1359
+ }
1360
+ }
1361
+ {
1362
+ "timestamp": "2026-02-11T05:45:40Z",
1363
+ "duration_ms": 0,
1364
+ "cost_usd": 0,
1365
+ "tokens_in": 0,
1366
+ "tokens_out": 0,
1367
+ "model": "unknown",
1368
+ "branch": "docs/v0.3.2-documentation-updates"
1369
+ }
1370
+ {
1371
+ "timestamp": "2026-02-11T05:45:40Z",
1372
+ "type": "cost_summary",
1373
+ "costs": {
1374
+ "other": 13
1375
+ }
1376
+ }
data/AGENTS.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # Repository Guidelines
2
2
 
3
- refer to ./ai/project_overview.md for full scope of this project
3
+ Refer to `CLAUDE.md` for project conventions and skills catalog.
4
4
 
5
- use rbenv for all ruby and bundler/gem commands, not the system ruby
5
+ Use rbenv for all ruby and bundler/gem commands, not the system ruby.
6
6
 
7
7
  ## Contribution Workflow
8
8
 
9
9
  - Treat the engine like any external contributor would: no direct commits to `main`.
10
- - Before writing code, branch off the latest `origin/main` (use a descriptive `feature/` or `bugfix/` prefix) and open a draft PR on `github.com/dchuk/source_monitor` referencing the active `.ai/tasks.md` slice.
10
+ - Before writing code, branch off the latest `origin/main` (use a descriptive `feature/` or `bugfix/` prefix) and open a draft PR on `github.com/dchuk/source_monitor`.
11
11
  - Push early and often to that branch so history stays visible; keep commits scoped and rebases local to your branch only.
12
12
  - Move the PR out of draft once tests pass and the slice is ready for review; request at least one review and wait for all CI jobs (lint, security, Rails tests + diff coverage) to succeed before merging.
13
13
  - The `test` job enforces diff coverage via `bin/check-diff-coverage`; if legitimate gaps remain after new code paths, refresh `config/coverage_baseline.json` by running `bin/test-coverage` followed by `bin/update-coverage-baseline` on the updated branch and commit the regenerated baseline.
@@ -59,7 +59,7 @@ Run `bin/setup` to install gems, prepare the dummy database, and compile Tailwin
59
59
 
60
60
  ## Coding Style & Naming Conventions
61
61
 
62
- Use two-space indentation and Ruby 3.3 syntax. Keep engine classes under the `SourceMonitor::` namespace; new modules should mirror their directory, e.g., `lib/source_monitor/fetching/pipeline.rb`. Favor service objects ending in `Service`, jobs ending in `Job`, and background channels ending in `Channel`. Rails defaults handle formatting, but run `bundle exec rubocop` (configured via `.rubocop.yml`) before opening a PR. For views, stick with ERB and Tailwind utility classes.
62
+ Use two-space indentation and Ruby 4.0+ syntax. Keep engine classes under the `SourceMonitor::` namespace; new modules should mirror their directory, e.g., `lib/source_monitor/fetching/pipeline.rb`. Favor service objects ending in `Service`, jobs ending in `Job`, and background channels ending in `Channel`. Rails defaults handle formatting, but run `bundle exec rubocop` (configured via `.rubocop.yml`) before opening a PR. For views, stick with ERB and Tailwind utility classes.
63
63
 
64
64
  ## Testing Guidelines
65
65
 
@@ -67,66 +67,29 @@ MiniTest drives coverage (`test/models`, `test/controllers`, `test/system`). Nam
67
67
 
68
68
  ## Commit & Pull Request Guidelines
69
69
 
70
- Adopt imperative commit messages in the format `scope: action`, e.g., `sources: enforce URL normalization`. Group unrelated work into separate commits. PRs should describe context, summarise the slice delivered, list validation steps (`bin/rails test`, manual fetch run), and reference roadmap items from `.ai/tasks.md`. Include screenshots or console output when altering UI or background jobs. Request at least one review and ensure CI completes before merge.
70
+ Adopt imperative commit messages in the format `scope: action`, e.g., `sources: enforce URL normalization`. Group unrelated work into separate commits. PRs should describe context, summarise the slice delivered, and list validation steps (`bin/rails test`, manual fetch run). Include screenshots or console output when altering UI or background jobs. Request at least one review and ensure CI completes before merge.
71
71
 
72
72
  ## Security & Configuration Tips
73
73
 
74
74
  Store secrets (API keys, webhook tokens) in `config/credentials/` and never commit plain-text values. When adding HTTP endpoints or webhooks, default to Solid Queue middleware for retries and respect the allowlist in `config/source_monitor.yml`. Document new environment variables in `config/application.yml.sample` and call out any migrations that impact host apps.
75
75
 
76
- # Clean coding guidelines
76
+ ## Clean Coding Principles
77
77
 
78
- Object Orientated Design: You should write code that embraces change. Here’s how…
78
+ - **SRP**: Classes and methods should have a single responsibility.
79
+ - **DRY**: Avoid duplication; changes should only need one edit.
80
+ - **Depend on behaviour, not data**: Wrap instance variables in methods (`attr_reader`); use Struct for data structures.
81
+ - **Minimise dependencies**: Use dependency injection, encapsulate external messages, prefer hash arguments.
82
+ - **Depend on things that change less often than you do.**
79
83
 
80
- SRP: A class should do the smallest possible useful thing; it should have a single responsibility. A class that has more than one responsibility is difficult to reuse. SRP requires that a class be cohesive, that everything the class does be highly related to its purpose. A class that is easy to reuse will make the application easier to change.
84
+ ## Claude Code Skills
81
85
 
82
- Methods, like classes, should have a single responsibility. All of the same reasons apply, having just one responsibility makes them easy to change and easy to reuse.
86
+ SourceMonitor ships 14 engine-specific Claude Code skills (`sm-*` prefix) covering the domain model, configuration DSL, pipeline stages, testing conventions, and more. Skills are distributed with the gem and installed into `.claude/skills/` via rake tasks:
83
87
 
84
- DRY: DRY code tolerates change because any change in behaviour can be made by changing code in just one place.
88
+ ```bash
89
+ bin/rails source_monitor:skills:install # Consumer skills (host app integration)
90
+ bin/rails source_monitor:skills:contributor # Contributor skills (engine development)
91
+ bin/rails source_monitor:skills:all # All skills
92
+ bin/rails source_monitor:skills:remove # Remove all sm-* skills
93
+ ```
85
94
 
86
- Depend on behaviour not data:
87
-
88
- Hide instance variables by wrapping them in a method, an attr_reader. The method changes a variable from data ( which is referenced all over) to behaviour (which is defined once). This means if you need to adjust the data you only have to make a change in one place.
89
-
90
- Hide data structures using the Struct class.
91
-
92
- Minimise Dependencies: An object depends on another object if, when one object changes, the other might be forced to change in turn. An object has a dependency when it knows:
93
-
94
- The name of another class.
95
-
96
- The name of a message that it intends to send to someone other than self.
97
-
98
- The arguments that a message requires.
99
-
100
- The order of those arguments.
101
-
102
- Dependency Injection: Addresses the first dependency. It decouples two objects by moving the creation of object_A outside of object_B eg:
103
-
104
- object_A.new(1,2,object_B.new)
105
-
106
- Encapsulation: Addresses the second dependency. Create wrapper methods so that external messages are isolated in one place. The wrapper method is called throughout the class, rather than sending messages externally.
107
-
108
- Use hashes for initialization arguments: this addresses the final dependencies.
109
-
110
- Depend on things that change less often than you do
111
-
112
- ## Agent Notes (2025-10-08)
113
-
114
- - Finished roadmap section 05.03 (structured fetch error handling). Added `SourceMonitor::Fetching::FetchError` hierarchy, expanded `FeedFetcher` error handling, and ensured instrumentation payloads include success/error context.
115
- - Fetch attempts now always create `FetchLog` records and update `Source` failure state; added MiniTest coverage for timeout, HTTP 404, and malformed feed scenarios.
116
- - Relevant tests: `bundle exec rails test test/lib/source_monitor/fetching/feed_fetcher_test.rb` and full suite via `bundle exec rails test` (both passing).
117
- - Next roadmap item is 05.04 (not started). Untracked tmp dir `test/lib/tmp` can be safely ignored if it reappears.
118
-
119
- ## Agent Notes (2025-10-09)
120
-
121
- - Introduced `SourceMonitor::Scrapers::Base`, establishing the scraper adapter contract and Result object. Subclasses merge default, source, and invocation settings (HashWithIndifferentAccess) and must return a Result with status/html/content/metadata. Use `SourceMonitor::Scrapers::Base.call(item:, source:, settings:, http:)` to execute adapters.
122
- - Added Readability scraper adapter leveraging SourceMonitor::HTTP, Nokolexbor, and ruby-readability. Supports override selectors via `scrape_settings[:selectors]`, records extraction metadata including strategy and inferred status, and returns structured failure results on HTTP errors.
123
- - Extracted scraper HTTP fetching and parsing into dedicated collaborators (`SourceMonitor::Scrapers::Fetchers::HttpFetcher` and `SourceMonitor::Scrapers::Parsers::ReadabilityParser`). The adapter now orchestrates these services, simplifying future parser additions while keeping failure metadata consistent.
124
- - Added Readability scraper adapter leveraging SourceMonitor::HTTP, Nokolexbor, and ruby-readability. Supports override selectors via `scrape_settings[:selectors]`, records extraction metadata including strategy and inferred status, and returns structured failure results on HTTP errors.
125
- - Phase 07.03 complete: introduced `SourceMonitor::ItemContent` table with one-to-one association, virtual accessors on `Item`, and migration that backfills existing scraped data while dropping legacy columns. Clearing both fields now removes the content row. Run `bundle exec rails db:migrate` in host apps after upgrading.
126
- - Phase 07.04 complete: added `SourceMonitor::Scraping::ItemScraper` service with log recording, manual scrape controls in the item admin, and a dedicated scraping configuration section on the source form. Item show page now highlights content comparisons, status badges, and recent scrape errors. System coverage updated to exercise the manual scraping flow.
127
- - Phase 08.02 complete: created `SourceMonitor::FetchFeedJob`, introduced `SourceMonitor::Fetching::FetchRunner` with Postgres advisory locking, and added a temporary `ScrapeItemJob` stub so new items from auto-scrape sources are queued with `scrape_status` set to `pending`. Manual fetch UI now reuses the runner, and tests cover job retry behavior plus follow-up scraping enqueue (`bundle exec rails test test/lib/source_monitor/fetching/fetch_runner_test.rb`, `bundle exec rails test test/jobs/source_monitor/fetch_feed_job_test.rb`, and `bundle exec rails test test/lib/source_monitor/fetching/feed_fetcher_test.rb`).
128
- - Phase 08.03 complete: implemented `SourceMonitor::Scraping::Enqueuer` with deduplication/auto-scrape guards, promoted `SourceMonitor::ScrapeItemJob` to execute `ItemScraper`, and updated the manual item view to enqueue jobs instead of running scrapes inline. Added unit coverage for the enqueuer/job plus refreshed the manual scrape system test (`bundle exec rails test test/lib/source_monitor/scraping/enqueuer_test.rb test/jobs/source_monitor/scrape_item_job_test.rb test/system/items_test.rb test/lib/source_monitor/fetching/fetch_runner_test.rb`).
129
- - Phase 08.04 complete: manual "Fetch Now" now queues `FetchFeedJob` via `FetchRunner.enqueue`, dashboard shows live queue metrics from `SourceMonitor::Jobs::Visibility`, and optional Mission Control link appears when configured. System tests updated to assert job enqueues (`test/system/sources_test.rb`, `test/system/items_test.rb`, `test/system/dashboard_test.rb`); run `bundle exec rails test test/system` after UI tweaks.
130
- - Install generator now also creates `config/initializers/source_monitor.rb` with documented defaults for queue settings, metrics, and Mission Control hooks. Update the initializer if future configuration options are added.
131
- - `SourceMonitor.mission_control_dashboard_path` now validates that the configured path exists before rendering a dashboard link, preventing 404s when Mission Control isn't mounted yet. Template comments outline how to mount the engine when enabling it.
132
- - `test/dummy/bin/dev` now runs the Rails server with `BUNDLE_GEMFILE` pointing at the dummy app, so dummy-only gems (like mission_control-jobs) load correctly while the Tailwind watcher still uses the engine's Gemfile.
95
+ See `CLAUDE.md` for the full skills catalog and usage details.
data/CHANGELOG.md CHANGED
@@ -15,6 +15,16 @@ All notable changes to this project are documented below. The format follows [Ke
15
15
 
16
16
  - No unreleased changes yet.
17
17
 
18
+ ## [0.3.2] - 2026-02-10
19
+
20
+ ### Fixed
21
+
22
+ - Updated README, AGENTS.md, CONTRIBUTING.md, and docs/ to reflect v0.3.1 changes (Ruby 4.0+, gem version refs, skills system documentation).
23
+ - Replaced stale `.ai/` references with `CLAUDE.md` and `AGENTS.md` across all docs.
24
+ - Corrected `SOURCE_MONITOR_TEST_WORKERS` env var to `PARALLEL_WORKERS` in CONTRIBUTING.md.
25
+ - Removed historical agent development notes from AGENTS.md.
26
+ - Condensed verbose clean coding guidelines into concise bullet summary.
27
+
18
28
  ## [0.3.1] - 2026-02-10
19
29
 
20
30
  ### Added
data/CLAUDE.md CHANGED
@@ -45,7 +45,7 @@ Run /vbw:help for all commands.
45
45
 
46
46
  | Layer | Technology |
47
47
  |-------|------------|
48
- | Ruby | 3.4+ |
48
+ | Ruby | 4.0+ |
49
49
  | Rails | 8.x |
50
50
  | Testing | Minitest (no fixtures -- uses factory helpers + WebMock/VCR) |
51
51
  | Authorization | Host app responsibility (mountable engine) |
data/CONTRIBUTING.md CHANGED
@@ -4,7 +4,7 @@ This project ships each roadmap slice behind a fast, reliable test loop. The not
4
4
 
5
5
  ## Test Suite Expectations
6
6
 
7
- - **Fast feedback:** run `bundle exec rake app:test:smoke` for unit, helper, and job coverage before pushing. Use `SOURCE_MONITOR_TEST_WORKERS=1` locally when profiling failures for determinism.
7
+ - **Fast feedback:** run `bundle exec rake app:test:smoke` for unit, helper, and job coverage before pushing. Use `PARALLEL_WORKERS=1` locally when profiling failures for determinism.
8
8
  - **Full validation:** continue to run `bundle exec rails test` (or `bin/test-coverage` in CI) before marking a slice ready for review.
9
9
  - **Background jobs:** the default adapter is `:test`. Switch to inline execution only for the precise block that needs it via `with_inline_jobs { ... }`; never flip the global adapter.
10
10
  - **Database usage:** prefer transactional fixtures over manual `delete_all`. Reach for `setup_once` (TestProf’s `before_all`) when immutable data can be shared safely across examples.
@@ -13,16 +13,16 @@ This project ships each roadmap slice behind a fast, reliable test loop. The not
13
13
  ## Performance Profiling
14
14
 
15
15
  - **Local commands:**
16
- - `TAG_PROF=type SOURCE_MONITOR_TEST_WORKERS=1 bundle exec rails test`
17
- - `EVENT_PROF=sql.active_record SOURCE_MONITOR_TEST_WORKERS=1 bundle exec rails test`
18
- - `TEST_STACK_PROF=1 SOURCE_MONITOR_TEST_WORKERS=1 bundle exec rails test test/integration`
16
+ - `TAG_PROF=type PARALLEL_WORKERS=1 bundle exec rails test`
17
+ - `EVENT_PROF=sql.active_record PARALLEL_WORKERS=1 bundle exec rails test`
18
+ - `TEST_STACK_PROF=1 PARALLEL_WORKERS=1 bundle exec rails test test/integration`
19
19
  - **CI automation:** a scheduled `profiling` workflow runs the commands above nightly, archives `tmp/test_prof`, and applies guardrails via `bin/check-test-prof-metrics` (suite ≤ 80s, integration ≤ 35s, DB time ≤ 5s). Failures block the job so regressions surface quickly.
20
20
 
21
21
  ## Code Review Checklist
22
22
 
23
23
  Before approval, verify that the changes:
24
24
 
25
- 1. Avoid unnecessary database persistence (`build_stubbed`/test doubles over `.create` when assertions allow).
25
+ 1. Avoid unnecessary database persistence (test doubles over `.create` when assertions allow).
26
26
  2. Share heavy setup with `setup_once` or helper memoization instead of per-test rebuilds.
27
27
  3. Scope inline job execution to `with_inline_jobs { ... }` blocks—no suite-wide adapter swaps.
28
28
  4. Keep new or modified system specs lean, relying on lower-level coverage when UI is not essential.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- source_monitor (0.3.1)
4
+ source_monitor (0.3.2)
5
5
  cssbundling-rails (~> 1.4)
6
6
  faraday (~> 2.9)
7
7
  faraday-follow_redirects (~> 0.4)
data/README.md CHANGED
@@ -9,8 +9,8 @@ SourceMonitor is a production-ready Rails 8 mountable engine for ingesting, norm
9
9
  In your host Rails app:
10
10
 
11
11
  ```bash
12
- bundle add source_monitor --version "~> 0.1.2"
13
- # or add `gem "source_monitor", "~> 0.1.2"` manually, then run:
12
+ bundle add source_monitor --version "~> 0.3.1"
13
+ # or add `gem "source_monitor", "~> 0.3.1"` manually, then run:
14
14
  bundle install
15
15
  ```
16
16
 
@@ -25,7 +25,7 @@ This exposes `bin/source_monitor` (via Bundler binstubs) so you can run the guid
25
25
  - First-class observability through ActiveSupport notifications and `SourceMonitor::Metrics` counters/gauges
26
26
 
27
27
  ## Requirements
28
- - Ruby 3.4.4 (we recommend [rbenv](https://github.com/rbenv/rbenv) for local development: `rbenv install 3.4.4 && rbenv local 3.4.4`, but use whatever Ruby version manager suits your environment—asdf, chruby, rvm, or container-based workflows all work fine)
28
+ - Ruby 4.0+ (we recommend [rbenv](https://github.com/rbenv/rbenv) for local development, but use whatever Ruby version manager suits your environment—asdf, chruby, rvm, or container-based workflows all work fine)
29
29
  - Rails ≥ 8.0.2.1 in the host application
30
30
  - PostgreSQL 13+ (engine migrations use JSONB, SKIP LOCKED, advisory locks, and Solid Cable tables)
31
31
  - Node.js 18+ (npm or Yarn) for asset linting and the Tailwind/esbuild bundling pipeline
@@ -41,7 +41,7 @@ This exposes `bin/source_monitor` (via Bundler binstubs) so you can run the guid
41
41
  Before running any SourceMonitor commands inside your host app, add the gem and install dependencies:
42
42
 
43
43
  ```bash
44
- bundle add source_monitor --version "~> 0.1.2"
44
+ bundle add source_monitor --version "~> 0.3.1"
45
45
  # or edit your Gemfile, then run
46
46
  bundle install
47
47
  ```
@@ -111,6 +111,19 @@ The generated initializer documents every setting. Key areas:
111
111
 
112
112
  See [docs/configuration.md](docs/configuration.md) for exhaustive coverage and examples.
113
113
 
114
+ ## Claude Code Skills
115
+
116
+ SourceMonitor ships 14 engine-specific Claude Code skills (`sm-*` prefix) that give AI agents deep context about the engine's domain model, configuration DSL, pipeline stages, and testing conventions. Skills are bundled with the gem and installed into your host app's `.claude/skills/` directory.
117
+
118
+ ```bash
119
+ bin/rails source_monitor:skills:install # Consumer skills (host app integration)
120
+ bin/rails source_monitor:skills:contributor # Contributor skills (engine development)
121
+ bin/rails source_monitor:skills:all # All skills
122
+ bin/rails source_monitor:skills:remove # Remove all sm-* skills
123
+ ```
124
+
125
+ The guided installer (`bin/source_monitor install`) also offers to install consumer skills as part of the setup workflow.
126
+
114
127
  ## Deployment Considerations
115
128
  - Copy engine migrations before every deploy and run `bin/rails db:migrate`.
116
129
  - Precompile assets so SourceMonitor's bundled CSS/JS outputs are available at runtime.
@@ -130,7 +143,7 @@ Common installation and runtime issues (missing migrations, realtime not streami
130
143
  - Quality checks: `bin/rubocop`, `bin/brakeman --no-pager`, `bin/lint-assets`.
131
144
  - Record HTTP fixtures with VCR under `test/vcr_cassettes/` and keep coverage ≥ 90% for new code.
132
145
 
133
- Contributions follow the clean architecture and TDD guidelines in `.ai/project_overview.md`. Review `.ai/tasks.md` to align with the active roadmap slice before opening a pull request.
146
+ Contributions follow the clean architecture and TDD guidelines in `CLAUDE.md` and `AGENTS.md`.
134
147
 
135
148
  ## License
136
149
  SourceMonitor is released under the [MIT License](MIT-LICENSE).
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.2
data/docs/deployment.md CHANGED
@@ -60,7 +60,7 @@ Keep this guide alongside your platform runbooks so teams can confidently deploy
60
60
 
61
61
  ## Container Reference Stack
62
62
 
63
- The repository ships a reusable Docker stack under `examples/docker` that mirrors the recommended process model. It builds a Ruby 3.3 image with Node, mounts your generated example via `APP_PATH`, and launches three services (`web`, `worker`, `scheduler`) alongside Postgres and Redis. Use it to trial production settings locally or as a baseline for ECS/Kubernetes manifests.
63
+ The repository ships a reusable Docker stack under `examples/docker` that mirrors the recommended process model. It builds a Ruby 4.0 image with Node, mounts your generated example via `APP_PATH`, and launches three services (`web`, `worker`, `scheduler`) alongside Postgres and Redis. Use it to trial production settings locally or as a baseline for ECS/Kubernetes manifests.
64
64
 
65
65
  ## Setup Workflow Rollout Checklist
66
66
 
data/docs/setup.md CHANGED
@@ -6,8 +6,8 @@ This guide consolidates the new guided installer, verification commands, and rol
6
6
 
7
7
  | Requirement | Minimum | Notes |
8
8
  | --- | --- | --- |
9
- | Ruby | 3.4.4 | Use rbenv and match the engine's `.ruby-version`. |
10
- | Rails | 8.0.2.1 | Run `bin/rails about` inside the host to confirm. |
9
+ | Ruby | 4.0.1 | Use rbenv and match the engine's `.ruby-version`. |
10
+ | Rails | 8.1.2 | Run `bin/rails about` inside the host to confirm. |
11
11
  | PostgreSQL | 14+ | Required for Solid Queue tables and item storage. |
12
12
  | Node.js | 18+ | Needed for Tailwind/esbuild assets when the host owns node tooling. |
13
13
  | Background jobs | Solid Queue (>= 0.3, < 3.0) | Add `solid_queue` to the host Gemfile if not present. |
@@ -18,8 +18,8 @@ This guide consolidates the new guided installer, verification commands, and rol
18
18
  Run these commands inside your host Rails application before invoking the guided workflow:
19
19
 
20
20
  ```bash
21
- bundle add source_monitor --version "~> 0.1.2"
22
- # or add gem "source_monitor", "~> 0.1.2" to Gemfile manually
21
+ bundle add source_monitor --version "~> 0.3.1"
22
+ # or add gem "source_monitor", "~> 0.3.1" to Gemfile manually
23
23
  bundle install
24
24
  ```
25
25
 
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+ require "pathname"
5
+
6
+ module SourceMonitor
7
+ module Setup
8
+ class SkillsInstaller
9
+ SM_SKILL_PATTERN = "sm-*"
10
+
11
+ CONSUMER_SKILLS = %w[
12
+ sm-host-setup sm-configure sm-scraper-adapter
13
+ sm-event-handler sm-model-extension sm-dashboard-widget
14
+ ].freeze
15
+
16
+ CONTRIBUTOR_SKILLS = %w[
17
+ sm-domain-model sm-architecture sm-engine-test
18
+ sm-configuration-setting sm-pipeline-stage sm-engine-migration
19
+ sm-job sm-health-rule
20
+ ].freeze
21
+
22
+ def initialize(gem_root: nil, output: $stdout)
23
+ @gem_root = Pathname.new(gem_root || resolve_gem_root)
24
+ @output = output
25
+ end
26
+
27
+ def install(target_dir:, group: :consumer)
28
+ target = Pathname.new(target_dir)
29
+ result = { installed: [], skipped: [] }
30
+
31
+ source_skills_dir = gem_root.join(".claude", "skills")
32
+ return result unless source_skills_dir.directory?
33
+
34
+ skill_dirs = Dir[source_skills_dir.join(SM_SKILL_PATTERN).to_s].sort
35
+ return result if skill_dirs.empty?
36
+
37
+ allowed = skills_for_group(group)
38
+ skill_dirs = skill_dirs.select { |path| allowed.include?(File.basename(path)) }
39
+ return result if skill_dirs.empty?
40
+
41
+ FileUtils.mkdir_p(target.to_s)
42
+
43
+ skill_dirs.each do |source_path|
44
+ skill_name = File.basename(source_path)
45
+ dest_path = target.join(skill_name)
46
+
47
+ if dest_path.directory?
48
+ result[:skipped] << skill_name
49
+ else
50
+ FileUtils.cp_r(source_path, dest_path.to_s)
51
+ result[:installed] << skill_name
52
+ end
53
+ end
54
+
55
+ result
56
+ end
57
+
58
+ def remove(target_dir:)
59
+ target = Pathname.new(target_dir)
60
+ result = { removed: [] }
61
+
62
+ return result unless target.directory?
63
+
64
+ Dir[target.join(SM_SKILL_PATTERN).to_s].sort.each do |path|
65
+ skill_name = File.basename(path)
66
+ FileUtils.rm_rf(path)
67
+ result[:removed] << skill_name
68
+ end
69
+
70
+ result
71
+ end
72
+
73
+ private
74
+
75
+ attr_reader :gem_root, :output
76
+
77
+ def skills_for_group(group)
78
+ case group
79
+ when :consumer then CONSUMER_SKILLS
80
+ when :contributor then CONTRIBUTOR_SKILLS
81
+ when :all then CONSUMER_SKILLS + CONTRIBUTOR_SKILLS
82
+ else raise ArgumentError, "Unknown skill group: #{group.inspect}. Use :consumer, :contributor, or :all"
83
+ end
84
+ end
85
+
86
+ def resolve_gem_root
87
+ spec = Gem.loaded_specs["source_monitor"]
88
+ return spec.gem_dir if spec
89
+
90
+ File.expand_path("../../..", __dir__)
91
+ end
92
+ end
93
+ end
94
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SourceMonitor
4
- VERSION = "0.3.1"
4
+ VERSION = "0.3.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: source_monitor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - dchuk
@@ -395,6 +395,7 @@ files:
395
395
  - MIT-LICENSE
396
396
  - README.md
397
397
  - Rakefile
398
+ - VERSION
398
399
  - app/assets/builds/.keep
399
400
  - app/assets/builds/source_monitor/application.css
400
401
  - app/assets/builds/source_monitor/application.js
@@ -642,6 +643,7 @@ files:
642
643
  - lib/source_monitor/setup/prompter.rb
643
644
  - lib/source_monitor/setup/requirements.rb
644
645
  - lib/source_monitor/setup/shell_runner.rb
646
+ - lib/source_monitor/setup/skills_installer.rb
645
647
  - lib/source_monitor/setup/verification/action_cable_verifier.rb
646
648
  - lib/source_monitor/setup/verification/printer.rb
647
649
  - lib/source_monitor/setup/verification/result.rb