rosett-ai 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (527) hide show
  1. checksums.yaml +7 -0
  2. data/.ai-provenance.yml +119 -0
  3. data/.debride_whitelist +186 -0
  4. data/.fasterer.yml +29 -0
  5. data/.mdl_style.rb +10 -0
  6. data/.mdlrc +3 -0
  7. data/.mutant.yml +49 -0
  8. data/.namespace-allowlist +42 -0
  9. data/.reek.yml +1040 -0
  10. data/.rosett-ai/config.yml +3 -0
  11. data/.rspec +5 -0
  12. data/.rubocop.yml +380 -0
  13. data/.ruby-version +1 -0
  14. data/.yamllint +51 -0
  15. data/.yardopts +12 -0
  16. data/AI-DISCLOSURE.md +48 -0
  17. data/CHANGELOG.md +519 -0
  18. data/CLAUDE.md +141 -0
  19. data/CONTRIBUTING.md +734 -0
  20. data/INSTALL.md +154 -0
  21. data/LICENSE +674 -0
  22. data/LICENSE.md +675 -0
  23. data/QUICKSTART.md +73 -0
  24. data/README.md +366 -0
  25. data/Rakefile +200 -0
  26. data/SECURITY.md +114 -0
  27. data/bin/rai +1 -0
  28. data/cliff.toml +52 -0
  29. data/conf/adopt_redactions.yml +8 -0
  30. data/conf/behaviour/.gitkeep +0 -0
  31. data/conf/compliance/cra_rules.yml +25 -0
  32. data/conf/compliance/license_rules.yml +20 -0
  33. data/conf/design/aaif_alignment.yml +181 -0
  34. data/conf/design/ab_testing.yml +172 -0
  35. data/conf/design/accessibility.yml +84 -0
  36. data/conf/design/ai_authorship.yml +210 -0
  37. data/conf/design/ai_provenance.yml +224 -0
  38. data/conf/design/ai_tool_configuration.yml +207 -0
  39. data/conf/design/architecture.yml +139 -0
  40. data/conf/design/autocompletion.yml +115 -0
  41. data/conf/design/backward_compatibility.yml +112 -0
  42. data/conf/design/behaviour_composition.yml +246 -0
  43. data/conf/design/build_rake_extraction.yml +57 -0
  44. data/conf/design/ci_pipeline.yml +100 -0
  45. data/conf/design/claude_code_configuration.yml +157 -0
  46. data/conf/design/compiler.yml +128 -0
  47. data/conf/design/comply.yml +153 -0
  48. data/conf/design/content_packs.yml +84 -0
  49. data/conf/design/desktop_integration.yml +289 -0
  50. data/conf/design/distribution.yml +216 -0
  51. data/conf/design/doctor.yml +184 -0
  52. data/conf/design/documentation.yml +152 -0
  53. data/conf/design/engine_architecture.yml +257 -0
  54. data/conf/design/error_handling.yml +103 -0
  55. data/conf/design/feature_flags.yml +142 -0
  56. data/conf/design/git_hooks.yml +165 -0
  57. data/conf/design/gui_plugins.yml +475 -0
  58. data/conf/design/i18n.yml +84 -0
  59. data/conf/design/integration_testing.yml +56 -0
  60. data/conf/design/licensing_system.yml +88 -0
  61. data/conf/design/lifecycle_management.yml +208 -0
  62. data/conf/design/mcp_integration.yml +207 -0
  63. data/conf/design/mcp_settings.yml +126 -0
  64. data/conf/design/migration.yml +56 -0
  65. data/conf/design/monitoring_observability.yml +194 -0
  66. data/conf/design/namespace_cleanup.yml +145 -0
  67. data/conf/design/plugin_test_segregation.yml +145 -0
  68. data/conf/design/policy_management.yml +229 -0
  69. data/conf/design/project_management.yml +183 -0
  70. data/conf/design/rai_mcp_asset_discovery.yml +164 -0
  71. data/conf/design/rai_mcp_server.yml +605 -0
  72. data/conf/design/release_management.yml +117 -0
  73. data/conf/design/retrofit.yml +199 -0
  74. data/conf/design/retrospective_analyzer.yml +79 -0
  75. data/conf/design/scope_hierarchy.yml +352 -0
  76. data/conf/design/security.yml +115 -0
  77. data/conf/design/session_retrospective.yml +85 -0
  78. data/conf/design/smart_ui_feedback.yml +89 -0
  79. data/conf/design/structured_logging.yml +148 -0
  80. data/conf/design/styles.yml +123 -0
  81. data/conf/design/test_peer_review.yml +89 -0
  82. data/conf/design/testing.yml +136 -0
  83. data/conf/design/threat_model.yml +108 -0
  84. data/conf/design/ui_framework.yml +111 -0
  85. data/conf/design/usage_optimization.yml +122 -0
  86. data/conf/design/version_management.yml +60 -0
  87. data/conf/design/workflow.yml +227 -0
  88. data/conf/mcp/server_defaults.yml +42 -0
  89. data/conf/mcp/trust.yml +21 -0
  90. data/conf/packaging/core.yml +12 -0
  91. data/conf/packaging/gtk4.yml +11 -0
  92. data/conf/packaging/qt6.yml +11 -0
  93. data/conf/policy/default_deny_list.yml +197 -0
  94. data/conf/review/cli-command-audit.yml +857 -0
  95. data/conf/review/design-docs.yml +1064 -0
  96. data/conf/review/design-questionnaire.yml +153 -0
  97. data/conf/review/questionnaire.yml +146 -0
  98. data/conf/review/rosett-ai-core.yml +2919 -0
  99. data/conf/schemas/ai_config_schema.json +73 -0
  100. data/conf/schemas/behaviour_schema.json +132 -0
  101. data/conf/schemas/compliance_rule_schema.json +63 -0
  102. data/conf/schemas/content_pack_manifest_schema.json +51 -0
  103. data/conf/schemas/design_schema.json +210 -0
  104. data/conf/schemas/engine_manifest_schema.json +144 -0
  105. data/conf/schemas/lockfile_schema.json +74 -0
  106. data/conf/schemas/mcp_server_schema.json +48 -0
  107. data/conf/schemas/packaging_schema.json +70 -0
  108. data/conf/schemas/policy_schema.json +85 -0
  109. data/conf/schemas/provenance_schema.json +84 -0
  110. data/conf/schemas/rai_config_schema.json +56 -0
  111. data/conf/schemas/rai_project_schema.json +20 -0
  112. data/conf/schemas/scope_hierarchy_schema.json +49 -0
  113. data/conf/schemas/target_schema.json +67 -0
  114. data/conf/schemas/tooling_schema.json +65 -0
  115. data/conf/schemas/workflow_schema.json +112 -0
  116. data/conf/targets/agents_md.yml +17 -0
  117. data/conf/targets/claude.yml +12 -0
  118. data/conf/tooling/tools.yml +58 -0
  119. data/dist/rosett-ai-mcp.service +48 -0
  120. data/dist/rosett-ai-mcp.yml.default +45 -0
  121. data/doc/AAIF_POSITIONING.md +58 -0
  122. data/doc/ADOPT.md +224 -0
  123. data/doc/AI_PROVENANCE.md +139 -0
  124. data/doc/ARCHITECTURE.md +920 -0
  125. data/doc/BEHAVIOUR.md +409 -0
  126. data/doc/BUILD.md +138 -0
  127. data/doc/CI_CD_RECIPES.md +171 -0
  128. data/doc/CLAUDE_SESSIONS_MOVED.md +16 -0
  129. data/doc/COMMAND_ANALYSIS.md +229 -0
  130. data/doc/CONFIGURATION.md +281 -0
  131. data/doc/DESIGN_AUDIT.md +235 -0
  132. data/doc/DESIGN_PEER_REVIEW.md +771 -0
  133. data/doc/DESKTOP.md +447 -0
  134. data/doc/ENGINES.md +567 -0
  135. data/doc/ENGINE_DEVELOPMENT_GUIDE.md +417 -0
  136. data/doc/FEATURE_AUDIT.md +218 -0
  137. data/doc/IMPLEMENTATION_PLAN.md +669 -0
  138. data/doc/INCIDENT_REPORT_2026-02-02.md +251 -0
  139. data/doc/MIGRATION_GUIDE.md +88 -0
  140. data/doc/PACKAGING.md +232 -0
  141. data/doc/PROJECT_DASHBOARD.md +153 -0
  142. data/doc/PULP_DEPLOYMENT.md +164 -0
  143. data/doc/QUALITY_FIX_SUMMARY.md +110 -0
  144. data/doc/QUICK_START.md +162 -0
  145. data/doc/REEK_CONFIGURATION.md +166 -0
  146. data/doc/REFERENCE.md +253 -0
  147. data/doc/REFERENCES.md +324 -0
  148. data/doc/SECURITY_REVIEW_CHECKLIST.md +72 -0
  149. data/doc/SESSION_2026-02-28_GTK4_HARDENING.md +359 -0
  150. data/doc/SETUP.md +202 -0
  151. data/doc/TEST_PEER_REVIEW.md +152 -0
  152. data/doc/THREAT_MODEL.md +230 -0
  153. data/doc/USAGE.md +545 -0
  154. data/doc/USER_MANUAL.md +585 -0
  155. data/doc/ai_test_review_checklist.md +110 -0
  156. data/doc/changes/2026-02-18-packaging-fpm.md +155 -0
  157. data/doc/changes/2026-02-19-testing-infrastructure.md +221 -0
  158. data/doc/changes/2026-02-20-security-implementation.md +281 -0
  159. data/doc/changes/2026-02-20-styles-implementation.md +220 -0
  160. data/doc/changes/2026-02-21-architecture-completion.md +95 -0
  161. data/doc/changes/2026-02-21-architecture-ui-layer.md +253 -0
  162. data/doc/changes/2026-02-21-cc-config-implementation.md +108 -0
  163. data/doc/changes/2026-02-21-ci-pipeline-implementation.md +214 -0
  164. data/doc/changes/2026-02-21-compiler-multi-target-pipeline.md +241 -0
  165. data/doc/changes/2026-02-21-config-design-show-commands.md +61 -0
  166. data/doc/changes/2026-02-21-design-implementation-overview.md +455 -0
  167. data/doc/changes/2026-02-21-lifecycle-management.md +196 -0
  168. data/doc/changes/2026-02-21-path-resolver.md +128 -0
  169. data/doc/changes/2026-02-24-ci-tmpdir-mutant-fetch.md +45 -0
  170. data/doc/changes/2026-03-01-ci-bundler-strategy.md +120 -0
  171. data/doc/changes/2026-03-20-security-hardening-phase2.md +163 -0
  172. data/doc/context/SESSION-HANDOFF.md +69 -0
  173. data/doc/context/ai-engine-usage-trends-2026.md +80 -0
  174. data/doc/context/plan-pluggable-engines.md +590 -0
  175. data/doc/decisions/001-flog-deferred.md +32 -0
  176. data/doc/decisions/002-path-resolution-strategy.md +158 -0
  177. data/doc/decisions/003-ui-adapter-selection.md +193 -0
  178. data/doc/decisions/004-design-document-validation.md +179 -0
  179. data/doc/decisions/005-package-splitting-strategy.md +200 -0
  180. data/doc/decisions/006-multi-engine-architecture.md +147 -0
  181. data/doc/decisions/007-engine-agnostic-pivot.md +219 -0
  182. data/doc/decisions/008-ci-bundler-strategy.md +129 -0
  183. data/doc/decisions/009-core-only-v1-release.md +60 -0
  184. data/doc/decisions/010-engine-debian-packaging.md +66 -0
  185. data/doc/decisions/011-context-aware-cli.md +71 -0
  186. data/doc/dependency_decisions.yml +247 -0
  187. data/doc/issues/001-wrapper-missing-environment-variables.md +197 -0
  188. data/doc/issues/002-embedded-ruby-wrong-prefix.md +217 -0
  189. data/doc/issues/003-smoke-test-false-positive.md +127 -0
  190. data/doc/issues/004-market-research-design-updates.md +109 -0
  191. data/doc/issues/005-compile-scope-coexistence.md +161 -0
  192. data/doc/locales/.gitkeep +0 -0
  193. data/doc/man/rai.1.ronn +505 -0
  194. data/doc/operations/packaging.md +133 -0
  195. data/doc/operations/rosett-ai-release.md +65 -0
  196. data/doc/reference/error-catalog.md +107 -0
  197. data/doc/reference/rosett-ai-technical-reference.pdf +0 -0
  198. data/doc/reference/src/Pictures/cover.jpg +0 -0
  199. data/doc/reference/src/Pictures/head1.jpg +0 -0
  200. data/doc/reference/src/Pictures/head2.jpg +0 -0
  201. data/doc/reference/src/Pictures/head3.jpg +0 -0
  202. data/doc/reference/src/Pictures/head4.jpg +0 -0
  203. data/doc/reference/src/Pictures/head5.jpg +0 -0
  204. data/doc/reference/src/Pictures/head6.jpg +0 -0
  205. data/doc/reference/src/Pictures/head7.jpg +0 -0
  206. data/doc/reference/src/Pictures/head8.jpg +0 -0
  207. data/doc/reference/src/StyleInd.ist +4 -0
  208. data/doc/reference/src/bibliography.bib +79 -0
  209. data/doc/reference/src/main.tex +1288 -0
  210. data/doc/reference/src/structure.tex +303 -0
  211. data/doc/rosett-ai-bookmarks.html +301 -0
  212. data/kitchen.yml +46 -0
  213. data/lib/rosett_ai/adopter/executor_resolver.rb +77 -0
  214. data/lib/rosett_ai/adopter/local_analysis_collector.rb +154 -0
  215. data/lib/rosett_ai/adopter/rule_adopter.rb +254 -0
  216. data/lib/rosett_ai/ai_config/config_compiler.rb +111 -0
  217. data/lib/rosett_ai/ai_config/context_window.rb +55 -0
  218. data/lib/rosett_ai/ai_config/cost_controls.rb +44 -0
  219. data/lib/rosett_ai/ai_config/fallback_chain.rb +64 -0
  220. data/lib/rosett_ai/ai_config/model_router.rb +121 -0
  221. data/lib/rosett_ai/ai_config/validator.rb +45 -0
  222. data/lib/rosett_ai/authorship/attribution_compiler.rb +99 -0
  223. data/lib/rosett_ai/authorship/disclosure_policy.rb +81 -0
  224. data/lib/rosett_ai/authorship/review_validator.rb +39 -0
  225. data/lib/rosett_ai/authorship/trailer_generator.rb +88 -0
  226. data/lib/rosett_ai/backup/compressor.rb +180 -0
  227. data/lib/rosett_ai/backup/destination.rb +91 -0
  228. data/lib/rosett_ai/behaviour/manager.rb +156 -0
  229. data/lib/rosett_ai/compiler/backend.rb +86 -0
  230. data/lib/rosett_ai/compiler/backends/agents_md_backend.rb +80 -0
  231. data/lib/rosett_ai/compiler/backends/claude_backend.rb +88 -0
  232. data/lib/rosett_ai/compiler/backends/generic_backend.rb +15 -0
  233. data/lib/rosett_ai/compiler/behaviour_compiler.rb +40 -0
  234. data/lib/rosett_ai/compiler/capability_checker.rb +104 -0
  235. data/lib/rosett_ai/compiler/compilation_pipeline.rb +361 -0
  236. data/lib/rosett_ai/compiler/compiled_output.rb +39 -0
  237. data/lib/rosett_ai/compiler/locale_compiler.rb +250 -0
  238. data/lib/rosett_ai/compiler/target_profile.rb +112 -0
  239. data/lib/rosett_ai/completion/generator.rb +101 -0
  240. data/lib/rosett_ai/completion/shells/bash_generator.rb +126 -0
  241. data/lib/rosett_ai/completion/shells/fish_generator.rb +78 -0
  242. data/lib/rosett_ai/completion/shells/zsh_generator.rb +126 -0
  243. data/lib/rosett_ai/comply/checkers/cra_checker.rb +102 -0
  244. data/lib/rosett_ai/comply/checkers/license_checker.rb +85 -0
  245. data/lib/rosett_ai/comply/checkers/spdx_header_checker.rb +98 -0
  246. data/lib/rosett_ai/comply/reporter.rb +113 -0
  247. data/lib/rosett_ai/comply/runner.rb +50 -0
  248. data/lib/rosett_ai/composition/circular_dependency_detector.rb +56 -0
  249. data/lib/rosett_ai/composition/composer.rb +158 -0
  250. data/lib/rosett_ai/composition/composition_result.rb +64 -0
  251. data/lib/rosett_ai/composition/conflict_detector.rb +53 -0
  252. data/lib/rosett_ai/composition/lockfile.rb +103 -0
  253. data/lib/rosett_ai/composition/merge_strategy.rb +131 -0
  254. data/lib/rosett_ai/composition/priority_sorter.rb +29 -0
  255. data/lib/rosett_ai/composition/scope_resolver.rb +55 -0
  256. data/lib/rosett_ai/config/compile_result.rb +37 -0
  257. data/lib/rosett_ai/config/compiler.rb +13 -0
  258. data/lib/rosett_ai/config/domain_transformer.rb +13 -0
  259. data/lib/rosett_ai/config/key_map.rb +13 -0
  260. data/lib/rosett_ai/config/masking_secret_resolver.rb +40 -0
  261. data/lib/rosett_ai/config/scope_router.rb +13 -0
  262. data/lib/rosett_ai/config/secret_resolver.rb +125 -0
  263. data/lib/rosett_ai/configuration.rb +119 -0
  264. data/lib/rosett_ai/content/content_client.rb +60 -0
  265. data/lib/rosett_ai/content/pack_installer.rb +117 -0
  266. data/lib/rosett_ai/content/pack_manifest.rb +50 -0
  267. data/lib/rosett_ai/content/pack_registry.rb +68 -0
  268. data/lib/rosett_ai/content_packs/manager.rb +50 -0
  269. data/lib/rosett_ai/dbus/compositor_detector.rb +77 -0
  270. data/lib/rosett_ai/dbus/focus_adapters/base.rb +59 -0
  271. data/lib/rosett_ai/dbus/focus_adapters/gnome_adapter.rb +172 -0
  272. data/lib/rosett_ai/dbus/focus_adapters/hyprland_adapter.rb +77 -0
  273. data/lib/rosett_ai/dbus/focus_adapters/i3_adapter.rb +65 -0
  274. data/lib/rosett_ai/dbus/focus_adapters/kwin_adapter.rb +103 -0
  275. data/lib/rosett_ai/dbus/focus_adapters/x11_adapter.rb +105 -0
  276. data/lib/rosett_ai/dbus/focus_monitor_interface.rb +103 -0
  277. data/lib/rosett_ai/dbus/manager_interface.rb +213 -0
  278. data/lib/rosett_ai/dbus/plugin_manager_interface.rb +169 -0
  279. data/lib/rosett_ai/dbus/rate_limiter.rb +89 -0
  280. data/lib/rosett_ai/dbus/service.rb +121 -0
  281. data/lib/rosett_ai/dbus/status_notifier_interface.rb +79 -0
  282. data/lib/rosett_ai/deprecation.rb +79 -0
  283. data/lib/rosett_ai/desktop/dbus_client.rb +259 -0
  284. data/lib/rosett_ai/desktop/gtk4_app.rb +371 -0
  285. data/lib/rosett_ai/desktop/gtk4_preferences.rb +331 -0
  286. data/lib/rosett_ai/desktop/gui_logger.rb +236 -0
  287. data/lib/rosett_ai/doctor/check.rb +92 -0
  288. data/lib/rosett_ai/doctor/checks/cache_health_check.rb +50 -0
  289. data/lib/rosett_ai/doctor/checks/dbus_availability_check.rb +39 -0
  290. data/lib/rosett_ai/doctor/checks/engine_detection_check.rb +46 -0
  291. data/lib/rosett_ai/doctor/checks/file_permission_check.rb +44 -0
  292. data/lib/rosett_ai/doctor/checks/gem_dependency_check.rb +55 -0
  293. data/lib/rosett_ai/doctor/checks/ruby_version_check.rb +50 -0
  294. data/lib/rosett_ai/doctor/checks/stale_config_nncc_check.rb +57 -0
  295. data/lib/rosett_ai/doctor/checks/stale_home_nncc_check.rb +59 -0
  296. data/lib/rosett_ai/doctor.rb +81 -0
  297. data/lib/rosett_ai/documentation/reference_compiler.rb +122 -0
  298. data/lib/rosett_ai/documentation/translator.rb +62 -0
  299. data/lib/rosett_ai/engines/base_config_compiler.rb +203 -0
  300. data/lib/rosett_ai/engines/detector.rb +63 -0
  301. data/lib/rosett_ai/engines/registry.rb +50 -0
  302. data/lib/rosett_ai/error_handler.rb +139 -0
  303. data/lib/rosett_ai/exit_codes.rb +76 -0
  304. data/lib/rosett_ai/feature_flags.rb +102 -0
  305. data/lib/rosett_ai/formatting.rb +33 -0
  306. data/lib/rosett_ai/gem_consistency_checker.rb +199 -0
  307. data/lib/rosett_ai/git_hooks/chain_detector.rb +86 -0
  308. data/lib/rosett_ai/git_hooks/installer.rb +175 -0
  309. data/lib/rosett_ai/git_hooks/script_generator.rb +125 -0
  310. data/lib/rosett_ai/gitlab/validators/supplementary_gitlab_ci_yaml_validator.rb +79 -0
  311. data/lib/rosett_ai/i18n/locale_resolver.rb +46 -0
  312. data/lib/rosett_ai/i18n/utf8_checker.rb +32 -0
  313. data/lib/rosett_ai/init/config_file_writer.rb +24 -0
  314. data/lib/rosett_ai/init/directory_builder.rb +38 -0
  315. data/lib/rosett_ai/init/file_copier.rb +95 -0
  316. data/lib/rosett_ai/init/global_initializer.rb +28 -0
  317. data/lib/rosett_ai/init/local_initializer.rb +27 -0
  318. data/lib/rosett_ai/init/mcp_registrar.rb +109 -0
  319. data/lib/rosett_ai/init/project_initializer.rb +38 -0
  320. data/lib/rosett_ai/licensing/license_key.rb +139 -0
  321. data/lib/rosett_ai/licensing/license_store.rb +64 -0
  322. data/lib/rosett_ai/licensing/license_validator.rb +60 -0
  323. data/lib/rosett_ai/licensing/tier.rb +42 -0
  324. data/lib/rosett_ai/mcp/admin/auditor.rb +88 -0
  325. data/lib/rosett_ai/mcp/admin/health_checker.rb +81 -0
  326. data/lib/rosett_ai/mcp/admin/registry.rb +100 -0
  327. data/lib/rosett_ai/mcp/admin/schema_validator.rb +63 -0
  328. data/lib/rosett_ai/mcp/enforcement/.gitkeep +0 -0
  329. data/lib/rosett_ai/mcp/enforcement/hook_generator.rb +197 -0
  330. data/lib/rosett_ai/mcp/enforcement/validator.rb +215 -0
  331. data/lib/rosett_ai/mcp/governance.rb +160 -0
  332. data/lib/rosett_ai/mcp/http_security_config.rb +158 -0
  333. data/lib/rosett_ai/mcp/instructions.rb +266 -0
  334. data/lib/rosett_ai/mcp/key_hasher.rb +66 -0
  335. data/lib/rosett_ai/mcp/keyfile.rb +221 -0
  336. data/lib/rosett_ai/mcp/middleware/authentication.rb +146 -0
  337. data/lib/rosett_ai/mcp/middleware/content_type.rb +56 -0
  338. data/lib/rosett_ai/mcp/middleware/cors.rb +83 -0
  339. data/lib/rosett_ai/mcp/middleware/origin_validation.rb +73 -0
  340. data/lib/rosett_ai/mcp/middleware/rate_limit.rb +106 -0
  341. data/lib/rosett_ai/mcp/middleware/request_size.rb +51 -0
  342. data/lib/rosett_ai/mcp/plugins.rb +143 -0
  343. data/lib/rosett_ai/mcp/prompts/compilation_prompt.rb +40 -0
  344. data/lib/rosett_ai/mcp/prompts/compliance_prompt.rb +41 -0
  345. data/lib/rosett_ai/mcp/prompts/diagnostics_prompt.rb +41 -0
  346. data/lib/rosett_ai/mcp/prompts/validation_prompt.rb +41 -0
  347. data/lib/rosett_ai/mcp/resources/behaviour_resource.rb +127 -0
  348. data/lib/rosett_ai/mcp/resources/config_resource.rb +72 -0
  349. data/lib/rosett_ai/mcp/resources/design_resource.rb +58 -0
  350. data/lib/rosett_ai/mcp/resources/hooks_resource.rb +74 -0
  351. data/lib/rosett_ai/mcp/resources/provenance_resource.rb +51 -0
  352. data/lib/rosett_ai/mcp/resources/rules_resource.rb +60 -0
  353. data/lib/rosett_ai/mcp/resources/schema_resource.rb +72 -0
  354. data/lib/rosett_ai/mcp/response_helper.rb +46 -0
  355. data/lib/rosett_ai/mcp/security_logger.rb +60 -0
  356. data/lib/rosett_ai/mcp/server.rb +212 -0
  357. data/lib/rosett_ai/mcp/settings/server_installer.rb +112 -0
  358. data/lib/rosett_ai/mcp/settings/trust_manager.rb +142 -0
  359. data/lib/rosett_ai/mcp/tools/adopt_tool.rb +70 -0
  360. data/lib/rosett_ai/mcp/tools/backup_tool.rb +64 -0
  361. data/lib/rosett_ai/mcp/tools/behaviour_display_tool.rb +72 -0
  362. data/lib/rosett_ai/mcp/tools/behaviour_list_tool.rb +56 -0
  363. data/lib/rosett_ai/mcp/tools/behaviour_manage_tool.rb +114 -0
  364. data/lib/rosett_ai/mcp/tools/behaviour_show_tool.rb +62 -0
  365. data/lib/rosett_ai/mcp/tools/compile_status_tool.rb +122 -0
  366. data/lib/rosett_ai/mcp/tools/compile_tool.rb +191 -0
  367. data/lib/rosett_ai/mcp/tools/comply_tool.rb +79 -0
  368. data/lib/rosett_ai/mcp/tools/config_compile_tool.rb +71 -0
  369. data/lib/rosett_ai/mcp/tools/config_status_tool.rb +79 -0
  370. data/lib/rosett_ai/mcp/tools/content_tool.rb +78 -0
  371. data/lib/rosett_ai/mcp/tools/context_query_tool.rb +156 -0
  372. data/lib/rosett_ai/mcp/tools/design_list_tool.rb +57 -0
  373. data/lib/rosett_ai/mcp/tools/design_show_tool.rb +69 -0
  374. data/lib/rosett_ai/mcp/tools/doctor_tool.rb +62 -0
  375. data/lib/rosett_ai/mcp/tools/documentation_status_tool.rb +45 -0
  376. data/lib/rosett_ai/mcp/tools/engines_tool.rb +84 -0
  377. data/lib/rosett_ai/mcp/tools/hook_install_tool.rb +190 -0
  378. data/lib/rosett_ai/mcp/tools/hook_preview_tool.rb +173 -0
  379. data/lib/rosett_ai/mcp/tools/hooks_status_tool.rb +84 -0
  380. data/lib/rosett_ai/mcp/tools/init_tool.rb +87 -0
  381. data/lib/rosett_ai/mcp/tools/license_status_tool.rb +44 -0
  382. data/lib/rosett_ai/mcp/tools/project_tool.rb +117 -0
  383. data/lib/rosett_ai/mcp/tools/provenance_tool.rb +97 -0
  384. data/lib/rosett_ai/mcp/tools/provenance_write_tool.rb +40 -0
  385. data/lib/rosett_ai/mcp/tools/retrofit_tool.rb +81 -0
  386. data/lib/rosett_ai/mcp/tools/rule_search_tool.rb +163 -0
  387. data/lib/rosett_ai/mcp/tools/schema_get_tool.rb +94 -0
  388. data/lib/rosett_ai/mcp/tools/tooling_tool.rb +86 -0
  389. data/lib/rosett_ai/mcp/tools/validate_tool.rb +105 -0
  390. data/lib/rosett_ai/mcp/tools/workflow_execute_tool.rb +74 -0
  391. data/lib/rosett_ai/mcp/tools/workflow_tool.rb +78 -0
  392. data/lib/rosett_ai/migration/detector.rb +117 -0
  393. data/lib/rosett_ai/migration/nncc_config_migrator.rb +94 -0
  394. data/lib/rosett_ai/migration/nncc_project_migrator.rb +90 -0
  395. data/lib/rosett_ai/migration/xdg_migrator.rb +123 -0
  396. data/lib/rosett_ai/package_manager/apt.rb +108 -0
  397. data/lib/rosett_ai/package_manager/base.rb +68 -0
  398. data/lib/rosett_ai/package_manager/gem_backend.rb +90 -0
  399. data/lib/rosett_ai/packaging/variant_config.rb +92 -0
  400. data/lib/rosett_ai/path_resolver.rb +115 -0
  401. data/lib/rosett_ai/plugins/contract.rb +43 -0
  402. data/lib/rosett_ai/plugins/engine_contract.rb +60 -0
  403. data/lib/rosett_ai/plugins/gui_contract.rb +74 -0
  404. data/lib/rosett_ai/plugins/mcp_contract.rb +48 -0
  405. data/lib/rosett_ai/plugins/registry.rb +150 -0
  406. data/lib/rosett_ai/policy/auditor.rb +41 -0
  407. data/lib/rosett_ai/policy/deny_list.rb +71 -0
  408. data/lib/rosett_ai/policy/opt_out_scanner.rb +37 -0
  409. data/lib/rosett_ai/policy/policy_compiler.rb +84 -0
  410. data/lib/rosett_ai/policy/protected_files.rb +47 -0
  411. data/lib/rosett_ai/policy/tier_hierarchy.rb +48 -0
  412. data/lib/rosett_ai/policy/validator.rb +35 -0
  413. data/lib/rosett_ai/profiler.rb +79 -0
  414. data/lib/rosett_ai/project/drift_detector.rb +126 -0
  415. data/lib/rosett_ai/project/manager.rb +115 -0
  416. data/lib/rosett_ai/project/sync_manager.rb +138 -0
  417. data/lib/rosett_ai/project/template_applier.rb +105 -0
  418. data/lib/rosett_ai/project_context.rb +82 -0
  419. data/lib/rosett_ai/provenance/entry.rb +63 -0
  420. data/lib/rosett_ai/provenance/file_source.rb +32 -0
  421. data/lib/rosett_ai/provenance/source.rb +62 -0
  422. data/lib/rosett_ai/provenance/store.rb +153 -0
  423. data/lib/rosett_ai/provenance/tracker.rb +62 -0
  424. data/lib/rosett_ai/provenance/trailer_generator.rb +43 -0
  425. data/lib/rosett_ai/provenance/validator.rb +45 -0
  426. data/lib/rosett_ai/quorum/collector.rb +59 -0
  427. data/lib/rosett_ai/quorum/comparator.rb +81 -0
  428. data/lib/rosett_ai/quorum/dispatcher.rb +57 -0
  429. data/lib/rosett_ai/quorum/strategies/adopt.rb +56 -0
  430. data/lib/rosett_ai/rai_config.rb +107 -0
  431. data/lib/rosett_ai/retrofit/base_parser.rb +66 -0
  432. data/lib/rosett_ai/retrofit/engine.rb +171 -0
  433. data/lib/rosett_ai/retrofit/parsers/agents_md_parser.rb +50 -0
  434. data/lib/rosett_ai/retrofit/parsers/claude_parser.rb +69 -0
  435. data/lib/rosett_ai/retrofit/parsers/cursor_parser.rb +82 -0
  436. data/lib/rosett_ai/retrofit/round_trip_validator.rb +65 -0
  437. data/lib/rosett_ai/retrofit/scanner.rb +47 -0
  438. data/lib/rosett_ai/retrofit/secret_detector.rb +87 -0
  439. data/lib/rosett_ai/secrets_resolver.rb +71 -0
  440. data/lib/rosett_ai/smart_feedback/suggester.rb +83 -0
  441. data/lib/rosett_ai/smart_feedback/thor_middleware.rb +84 -0
  442. data/lib/rosett_ai/structured_logger.rb +110 -0
  443. data/lib/rosett_ai/telemetry/json_lines_writer.rb +50 -0
  444. data/lib/rosett_ai/telemetry/log_rotator.rb +67 -0
  445. data/lib/rosett_ai/telemetry/provider.rb +26 -0
  446. data/lib/rosett_ai/telemetry/reporter.rb +144 -0
  447. data/lib/rosett_ai/telemetry.rb +47 -0
  448. data/lib/rosett_ai/text_sanitizer.rb +62 -0
  449. data/lib/rosett_ai/thor/cli.rb +269 -0
  450. data/lib/rosett_ai/thor/tasks/adopt.rb +250 -0
  451. data/lib/rosett_ai/thor/tasks/backup.rb +420 -0
  452. data/lib/rosett_ai/thor/tasks/behaviour.rb +474 -0
  453. data/lib/rosett_ai/thor/tasks/build.rb +1162 -0
  454. data/lib/rosett_ai/thor/tasks/compile.rb +415 -0
  455. data/lib/rosett_ai/thor/tasks/completion.rb +123 -0
  456. data/lib/rosett_ai/thor/tasks/comply.rb +82 -0
  457. data/lib/rosett_ai/thor/tasks/config.rb +265 -0
  458. data/lib/rosett_ai/thor/tasks/content.rb +193 -0
  459. data/lib/rosett_ai/thor/tasks/dbus.rb +321 -0
  460. data/lib/rosett_ai/thor/tasks/design.rb +258 -0
  461. data/lib/rosett_ai/thor/tasks/desktop.rb +129 -0
  462. data/lib/rosett_ai/thor/tasks/doctor.rb +127 -0
  463. data/lib/rosett_ai/thor/tasks/documentation.rb +321 -0
  464. data/lib/rosett_ai/thor/tasks/engines.rb +167 -0
  465. data/lib/rosett_ai/thor/tasks/hooks.rb +219 -0
  466. data/lib/rosett_ai/thor/tasks/init.rb +259 -0
  467. data/lib/rosett_ai/thor/tasks/license.rb +120 -0
  468. data/lib/rosett_ai/thor/tasks/mcp.rb +535 -0
  469. data/lib/rosett_ai/thor/tasks/migrate.rb +121 -0
  470. data/lib/rosett_ai/thor/tasks/plugins.rb +157 -0
  471. data/lib/rosett_ai/thor/tasks/project.rb +260 -0
  472. data/lib/rosett_ai/thor/tasks/provenance.rb +195 -0
  473. data/lib/rosett_ai/thor/tasks/release.rb +314 -0
  474. data/lib/rosett_ai/thor/tasks/retrofit.rb +90 -0
  475. data/lib/rosett_ai/thor/tasks/tooling.rb +308 -0
  476. data/lib/rosett_ai/thor/tasks/validate.rb +108 -0
  477. data/lib/rosett_ai/thor/tasks/workflow.rb +196 -0
  478. data/lib/rosett_ai/tooling/ci_yaml_validator.rb +37 -0
  479. data/lib/rosett_ai/tooling/version_checker.rb +35 -0
  480. data/lib/rosett_ai/ui/accessible_tui.rb +61 -0
  481. data/lib/rosett_ai/ui/base.rb +46 -0
  482. data/lib/rosett_ai/ui/gtk4.rb +98 -0
  483. data/lib/rosett_ai/ui/kde.rb +40 -0
  484. data/lib/rosett_ai/ui/qt6.rb +40 -0
  485. data/lib/rosett_ai/ui/registry.rb +60 -0
  486. data/lib/rosett_ai/ui/tty_helper.rb +74 -0
  487. data/lib/rosett_ai/ui/tui.rb +59 -0
  488. data/lib/rosett_ai/validators/behaviour_validator.rb +20 -0
  489. data/lib/rosett_ai/validators/design_validator.rb +17 -0
  490. data/lib/rosett_ai/validators/schema_validator.rb +84 -0
  491. data/lib/rosett_ai/validators/tooling_validator.rb +17 -0
  492. data/lib/rosett_ai/version.rb +8 -0
  493. data/lib/rosett_ai/version_consistency_checker.rb +129 -0
  494. data/lib/rosett_ai/workflow/audit_log.rb +86 -0
  495. data/lib/rosett_ai/workflow/engine.rb +142 -0
  496. data/lib/rosett_ai/workflow/manager.rb +82 -0
  497. data/lib/rosett_ai/workflow/schema_validator.rb +71 -0
  498. data/lib/rosett_ai/workflow/step_runner.rb +61 -0
  499. data/lib/rosett_ai/workflow/steps/prompt_step.rb +62 -0
  500. data/lib/rosett_ai/workflow/steps/rai_step.rb +74 -0
  501. data/lib/rosett_ai/workflow/steps/shell_step.rb +53 -0
  502. data/lib/rosett_ai/yaml_loader.rb +78 -0
  503. data/lib/rosett_ai.rb +221 -0
  504. data/lib/rubocop/cop/rosett_ai/shell_interpolation.rb +54 -0
  505. data/lib/rubocop/cop/rosett_ai/unsafe_const_get.rb +60 -0
  506. data/lib/rubocop/cop/rosett_ai/unsafe_send.rb +50 -0
  507. data/lib/rubocop/cop/rosett_ai/unsafe_yaml_load.rb +40 -0
  508. data/lib/rubocop/rosett_ai.rb +9 -0
  509. data/lib/scripts/generated/docker_hub_tags.rb +126 -0
  510. data/locales/.gitkeep +0 -0
  511. data/locales/ar.yml +579 -0
  512. data/locales/en.yml +571 -0
  513. data/locales/fr.yml +567 -0
  514. data/packaging/build-engine-deb.sh +81 -0
  515. data/packaging/scripts/postinst +17 -0
  516. data/packaging/scripts/postrm +19 -0
  517. data/packaging/scripts/prerm +10 -0
  518. data/packaging/wrapper.sh.template +38 -0
  519. data/rosett-ai.gemspec +63 -0
  520. data/rules/.gitkeep +0 -0
  521. data/scripts/publish/pulp_upload.sh +123 -0
  522. data/settings.json +29 -0
  523. data/share/applications/be.neatnerds.rosettai.desktop +29 -0
  524. data/share/dbus-1/interfaces/be.neatnerds.rosettai.xml +103 -0
  525. data/share/dbus-1/services/be.neatnerds.rosettai.service +3 -0
  526. data/share/templates/behaviour/criticalthinking.yml +69 -0
  527. metadata +810 -0
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ module RosettAi
7
+ module Mcp
8
+ module Middleware
9
+ # Rack middleware that enforces maximum request body size.
10
+ #
11
+ # Returns 413 Payload Too Large for oversized requests.
12
+ # Default limit: 1 MB.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class RequestSize
17
+ DEFAULT_MAX_SIZE = 1_048_576 # 1 MB
18
+
19
+ # @param app [#call] the next Rack application
20
+ # @param max_size [Integer] maximum request body size in bytes
21
+ def initialize(app, max_size: DEFAULT_MAX_SIZE)
22
+ @app = app
23
+ @max_size = max_size
24
+ end
25
+
26
+ # @param env [Hash] Rack environment
27
+ # @return [Array] Rack response triplet
28
+ def call(env)
29
+ content_length = env['CONTENT_LENGTH'].to_i
30
+ return payload_too_large(content_length) if content_length > @max_size
31
+
32
+ @app.call(env)
33
+ end
34
+
35
+ private
36
+
37
+ def payload_too_large(size)
38
+ body = JSON.generate(
39
+ jsonrpc: '2.0',
40
+ error: {
41
+ code: -32_600,
42
+ message: "Payload too large (#{size} bytes, max #{@max_size})"
43
+ },
44
+ id: nil
45
+ )
46
+ [413, { 'content-type' => 'application/json' }, [body]]
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ module RosettAi
7
+ module Mcp
8
+ # Plugin auto-discovery and loading for MCP server.
9
+ #
10
+ # Discovers installed gems named `rosett-ai-mcp-*` and loads them
11
+ # as MCP server plugins. Convention: gem `rosett-ai-mcp-foo` defines
12
+ # `RosettAiMcp::Plugins::Foo` with a `.register(server)` method.
13
+ #
14
+ # Governance (built-in tools) is always loaded first.
15
+ #
16
+ # @author hugo
17
+ # @author claude
18
+ module Plugins
19
+ PLUGIN_MUTEX = Mutex.new
20
+
21
+ module_function
22
+
23
+ # Register a plugin class by name.
24
+ #
25
+ # @param name [Symbol] plugin name
26
+ # @param plugin_class [Class] plugin class with .register(server)
27
+ # @return [void]
28
+ def register(name, plugin_class)
29
+ PLUGIN_MUTEX.synchronize { plugin_registry[name.to_sym] = plugin_class }
30
+ end
31
+
32
+ # Check if a plugin is available (registered or gem installed).
33
+ #
34
+ # @param name [Symbol, String] plugin name
35
+ # @return [Boolean]
36
+ def available?(name)
37
+ PLUGIN_MUTEX.synchronize { plugin_registry.key?(name.to_sym) } || gem_available?(name)
38
+ end
39
+
40
+ # Load all discovered plugins and register with server.
41
+ #
42
+ # @param server [MCP::Server] the MCP server instance
43
+ # @param plugin_names [Array<String>] explicit plugins to load
44
+ # @return [Array<Symbol>] loaded plugin names
45
+ def load_all(server, plugin_names = [])
46
+ discovered = discover_plugin_gems
47
+ all_plugins = (discovered + plugin_names.map(&:to_sym)).uniq
48
+ loaded = []
49
+
50
+ all_plugins.each do |name|
51
+ loaded << name if load_plugin(server, name)
52
+ end
53
+ loaded
54
+ end
55
+
56
+ # Load a single plugin by name.
57
+ #
58
+ # @param server [MCP::Server] the MCP server instance
59
+ # @param name [Symbol, String] plugin name
60
+ # @return [Boolean] true if loaded successfully
61
+ def load_plugin(server, name)
62
+ sym = name.to_sym
63
+ plugin_class = PLUGIN_MUTEX.synchronize { plugin_registry[sym] }
64
+
65
+ if plugin_class
66
+ plugin_class.register(server)
67
+ return true
68
+ end
69
+
70
+ require_and_register_gem(server, sym)
71
+ rescue StandardError, LoadError => e
72
+ warn "[rai-mcp] Plugin load failed for #{name}: #{e.message}"
73
+ false
74
+ end
75
+
76
+ # Discover installed gems named rosett-ai-mcp-*.
77
+ #
78
+ # @return [Array<Symbol>] discovered plugin names
79
+ def discover_plugin_gems
80
+ discovered = []
81
+ Gem::Specification.each do |spec|
82
+ next unless spec.name.start_with?('rosett-ai-mcp-') && spec.name != 'rosett-ai-mcp'
83
+
84
+ plugin_name = spec.name.sub('rosett-ai-mcp-', '')
85
+ discovered << plugin_name.to_sym
86
+ end
87
+ discovered
88
+ rescue StandardError
89
+ []
90
+ end
91
+
92
+ # Read-only access to the plugin registry.
93
+ #
94
+ # @return [Hash] registered plugins
95
+ def registry
96
+ PLUGIN_MUTEX.synchronize { plugin_registry.dup }
97
+ end
98
+
99
+ # Reset the registry (for testing).
100
+ #
101
+ # @return [void]
102
+ def reset!
103
+ PLUGIN_MUTEX.synchronize { plugin_registry.clear }
104
+ end
105
+
106
+ # Thread-safe access to the plugin store.
107
+ #
108
+ # @return [Hash] mutable registry hash
109
+ def plugin_registry
110
+ @plugin_registry ||= {} # rubocop:disable ThreadSafety/ClassInstanceVariable
111
+ end
112
+
113
+ # Allowlist prefix for plugin constant resolution.
114
+ PLUGIN_NAMESPACE = 'RosettAiMcp::Plugins::'
115
+
116
+ class << self
117
+ private
118
+
119
+ def gem_available?(name)
120
+ Gem::Specification.find_by_name("rosett-ai-mcp-#{name}")
121
+ true
122
+ rescue Gem::MissingSpecError
123
+ false
124
+ end
125
+
126
+ def require_and_register_gem(server, name) # rubocop:disable Naming/PredicateMethod
127
+ gem_name = "rosett-ai-mcp-#{name}"
128
+ require gem_name.tr('-', '_')
129
+
130
+ plugin_class_name = name.to_s.split(/[-_]/).map(&:capitalize).join
131
+ qualified_name = "#{PLUGIN_NAMESPACE}#{plugin_class_name}"
132
+
133
+ # Safe constant resolution via Object.const_get with validated name
134
+ raise ArgumentError, "Invalid plugin name: #{name}" unless plugin_class_name.match?(/\A[A-Z][a-zA-Z0-9]*\z/)
135
+
136
+ plugin_module = Object.const_get(qualified_name) # rubocop:disable RosettAi/UnsafeConstGet
137
+ plugin_module.register(server)
138
+ true
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ module RosettAi
7
+ module Mcp
8
+ module Prompts
9
+ # MCP prompt: compilation workflow.
10
+ #
11
+ # Provides a structured prompt for AI agents to compile
12
+ # rai behaviours and review the output.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class CompilationPrompt
17
+ PROMPT_NAME = 'rai_compilation_workflow'
18
+ DESCRIPTION = 'Compile rai behaviours and review output'
19
+
20
+ # Generates the compilation prompt messages.
21
+ #
22
+ # @param engine [String] target engine (default 'claude')
23
+ # @return [Array<Hash>] MCP prompt messages
24
+ def call(engine: 'claude')
25
+ [
26
+ {
27
+ role: 'user',
28
+ content: {
29
+ type: 'text',
30
+ text: "Please compile rai behaviours for the '#{engine}' engine. " \
31
+ 'First run nncc_compile with simulate=true to preview changes, ' \
32
+ 'then review the diffs before confirming compilation.'
33
+ }
34
+ }
35
+ ]
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ module RosettAi
7
+ module Mcp
8
+ module Prompts
9
+ # MCP prompt: compliance workflow.
10
+ #
11
+ # Provides a structured prompt for AI agents to run compliance
12
+ # checks and interpret the results.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class CompliancePrompt
17
+ PROMPT_NAME = 'rai_compliance_workflow'
18
+ DESCRIPTION = 'Run compliance checks and interpret results'
19
+
20
+ # Generates the compliance prompt messages.
21
+ #
22
+ # @param scope [String, nil] optional scope ('cra', 'license', 'headers')
23
+ # @return [Array<Hash>] MCP prompt messages
24
+ def call(scope: nil)
25
+ scope_text = scope ? " focusing on #{scope} checks" : ''
26
+ [
27
+ {
28
+ role: 'user',
29
+ content: {
30
+ type: 'text',
31
+ text: "Please run rosett-ai compliance checks#{scope_text}. " \
32
+ 'Use the Rosett-AI_comply tool to check for violations, then ' \
33
+ 'review any findings and suggest remediation steps.'
34
+ }
35
+ }
36
+ ]
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ module RosettAi
7
+ module Mcp
8
+ module Prompts
9
+ # MCP prompt: diagnostics workflow.
10
+ #
11
+ # Provides a structured prompt for AI agents to run diagnostics
12
+ # and troubleshoot issues.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class DiagnosticsPrompt
17
+ PROMPT_NAME = 'rai_diagnostics_workflow'
18
+ DESCRIPTION = 'Run diagnostics and troubleshoot issues'
19
+
20
+ # Generates the diagnostics prompt messages.
21
+ #
22
+ # @param check [String, nil] specific check to focus on
23
+ # @return [Array<Hash>] MCP prompt messages
24
+ def call(check: nil)
25
+ check_text = check ? " specifically the '#{check}' check" : ''
26
+ [
27
+ {
28
+ role: 'user',
29
+ content: {
30
+ type: 'text',
31
+ text: "Please run rosett-ai diagnostics#{check_text}. " \
32
+ 'Use the Rosett-AI_doctor tool to check system health, then ' \
33
+ 'review any failures and suggest troubleshooting steps.'
34
+ }
35
+ }
36
+ ]
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ module RosettAi
7
+ module Mcp
8
+ module Prompts
9
+ # MCP prompt: validation workflow.
10
+ #
11
+ # Provides a structured prompt for AI agents to validate
12
+ # rai configuration and suggest fixes for any issues found.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class ValidationPrompt
17
+ PROMPT_NAME = 'rai_validation_workflow'
18
+ DESCRIPTION = 'Validate rai configuration and suggest fixes'
19
+
20
+ # Generates the validation prompt messages.
21
+ #
22
+ # @param scope [String, nil] optional scope filter
23
+ # @return [Array<Hash>] MCP prompt messages
24
+ def call(scope: nil)
25
+ scope_text = scope ? " for scope '#{scope}'" : ''
26
+ [
27
+ {
28
+ role: 'user',
29
+ content: {
30
+ type: 'text',
31
+ text: "Please validate all rai configuration files#{scope_text}. " \
32
+ 'Use the Rosett-AI_validate tool to check for errors, then review ' \
33
+ 'any issues found and suggest specific fixes.'
34
+ }
35
+ }
36
+ ]
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ module RosettAi
7
+ module Mcp
8
+ module Resources
9
+ # MCP resource provider for rai behaviour files.
10
+ #
11
+ # Exposes behaviour YAML files as MCP resources with 3-tier lookup:
12
+ # project > XDG user > packaged. Supports tier query parameter
13
+ # to request a specific tier.
14
+ #
15
+ # URIs: rosett-ai://behaviour/{name}
16
+ # rosett-ai://behaviour/{name}?tier=xdg
17
+ #
18
+ # @author hugo
19
+ # @author claude
20
+ class BehaviourResource
21
+ URI_PREFIX = 'rosett-ai://behaviour/'
22
+
23
+ TIER_DIRS = {
24
+ 'project' => -> { RosettAi.conf_root.join('conf', 'behaviour') },
25
+ 'xdg' => -> { RosettAi.paths.rai_conf_dir.join('behaviour') },
26
+ 'packaged' => -> { RosettAi.paths.packaged_conf_dir.join('behaviour') }
27
+ }.freeze
28
+
29
+ # Lists all available behaviour resources across all tiers.
30
+ #
31
+ # @return [Array<Hash>] resource entries with :uri, :name, :description
32
+ def list
33
+ names = Set.new
34
+ tier_dirs.each_value do |dir|
35
+ next unless dir.directory?
36
+
37
+ dir.glob('*.yml').each { |path| names << path.basename('.yml').to_s }
38
+ end
39
+
40
+ names.sort.map { |name| resource_entry(name) }
41
+ end
42
+
43
+ # Reads a specific behaviour resource via 3-tier lookup.
44
+ #
45
+ # @param name [String] behaviour name, optionally with ?tier= query
46
+ # @return [Hash, nil] resource content with :uri, :content, :mime_type
47
+ def read(name)
48
+ base_name, tier = parse_name_and_tier(name)
49
+ path = tier ? find_in_tier(base_name, tier) : find_first(base_name)
50
+ return nil unless path&.exist?
51
+
52
+ {
53
+ uri: "#{URI_PREFIX}#{base_name}",
54
+ content: File.read(path),
55
+ mime_type: 'application/x-yaml',
56
+ tier: tier || detected_tier(path)
57
+ }
58
+ end
59
+
60
+ private
61
+
62
+ # @return [Hash{String => Pathname}]
63
+ def tier_dirs
64
+ TIER_DIRS.transform_values(&:call)
65
+ end
66
+
67
+ # @param raw [String] e.g. "criticalthinking?tier=xdg"
68
+ # @return [Array(String, String)] [base_name, tier]
69
+ def parse_name_and_tier(raw)
70
+ if raw.include?('?')
71
+ base, query = raw.split('?', 2)
72
+ tier = query[/tier=(\w+)/, 1]
73
+ [base, tier]
74
+ else
75
+ [raw, nil]
76
+ end
77
+ end
78
+
79
+ # @param name [String]
80
+ # @param tier [String]
81
+ # @return [Pathname, nil]
82
+ def find_in_tier(name, tier)
83
+ dir = tier_dirs[tier]
84
+ return nil unless dir&.directory?
85
+
86
+ path = dir.join("#{name}.yml")
87
+ path.exist? ? path : nil
88
+ end
89
+
90
+ # First-wins lookup: project > xdg > packaged.
91
+ #
92
+ # @param name [String]
93
+ # @return [Pathname, nil]
94
+ def find_first(name)
95
+ tier_dirs.each_value do |dir|
96
+ next unless dir.directory?
97
+
98
+ path = dir.join("#{name}.yml")
99
+ return path if path.exist?
100
+ end
101
+ nil
102
+ end
103
+
104
+ # @param path [Pathname]
105
+ # @return [String]
106
+ def detected_tier(path)
107
+ path_str = path.to_s
108
+ tier_dirs.each do |tier, dir|
109
+ return tier if path_str.start_with?(dir.to_s)
110
+ end
111
+ 'unknown'
112
+ end
113
+
114
+ # @param name [String]
115
+ # @return [Hash]
116
+ def resource_entry(name)
117
+ {
118
+ uri: "#{URI_PREFIX}#{name}",
119
+ name: name,
120
+ description: "Behaviour configuration: #{name}",
121
+ mime_type: 'application/x-yaml'
122
+ }
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ module RosettAi
7
+ module Mcp
8
+ module Resources
9
+ # MCP resource provider for compiled configuration.
10
+ #
11
+ # Exposes compiled configuration scopes as MCP resources.
12
+ #
13
+ # @author hugo
14
+ # @author claude
15
+ class ConfigResource
16
+ URI_PREFIX = 'rosett-ai://config/'
17
+ SCOPES = ['managed', 'user', 'project', 'local'].freeze
18
+
19
+ # Lists available config resources.
20
+ #
21
+ # @return [Array<Hash>] resource entries
22
+ def list
23
+ SCOPES.filter_map do |scope|
24
+ path = scope_path(scope)
25
+ next unless path&.exist?
26
+
27
+ {
28
+ uri: "#{URI_PREFIX}#{scope}",
29
+ name: "config-#{scope}",
30
+ description: "Compiled configuration: #{scope} scope",
31
+ mime_type: 'application/json'
32
+ }
33
+ end
34
+ end
35
+
36
+ # Reads a specific config scope.
37
+ #
38
+ # @param scope [String] scope name (managed, user, project, local)
39
+ # @return [Hash, nil] resource content
40
+ def read(scope)
41
+ return nil unless SCOPES.include?(scope)
42
+
43
+ path = scope_path(scope)
44
+ return nil unless path&.exist?
45
+
46
+ {
47
+ uri: "#{URI_PREFIX}#{scope}",
48
+ content: File.read(path),
49
+ mime_type: 'application/json'
50
+ }
51
+ end
52
+
53
+ private
54
+
55
+ # @param scope [String]
56
+ # @return [Pathname, nil]
57
+ def scope_path(scope)
58
+ case scope
59
+ when 'managed'
60
+ Pathname.new(File.expand_path('~/.claude/settings.json'))
61
+ when 'user'
62
+ Pathname.new(File.expand_path('~/.claude/settings.local.json'))
63
+ when 'project'
64
+ RosettAi.root.join('.claude', 'settings.json')
65
+ when 'local'
66
+ RosettAi.root.join('.claude', 'settings.local.json')
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ module RosettAi
7
+ module Mcp
8
+ module Resources
9
+ # MCP resource provider for rai design documents.
10
+ #
11
+ # Exposes design YAML files as MCP resources with
12
+ # URIs in the format rosett-ai://design/{name}.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class DesignResource
17
+ URI_PREFIX = 'rosett-ai://design/'
18
+
19
+ # Lists all available design resources.
20
+ #
21
+ # @return [Array<Hash>] resource entries with :uri, :name, :description
22
+ def list
23
+ dir = RosettAi.root.join('conf', 'design')
24
+ return [] unless dir.directory?
25
+
26
+ dir.glob('*.yml').map { |path| resource_entry(path) }
27
+ end
28
+
29
+ # Reads a specific design resource.
30
+ #
31
+ # @param name [String] design name (without .yml)
32
+ # @return [Hash, nil] resource content with :uri, :content, :mime_type
33
+ def read(name)
34
+ path = RosettAi.root.join('conf', 'design', "#{name}.yml")
35
+ return nil unless path.exist?
36
+
37
+ {
38
+ uri: "#{URI_PREFIX}#{name}",
39
+ content: File.read(path),
40
+ mime_type: 'application/x-yaml'
41
+ }
42
+ end
43
+
44
+ private
45
+
46
+ def resource_entry(path)
47
+ name = path.basename('.yml').to_s
48
+ {
49
+ uri: "#{URI_PREFIX}#{name}",
50
+ name: name,
51
+ description: "Design document: #{name}",
52
+ mime_type: 'application/x-yaml'
53
+ }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ module RosettAi
7
+ module Mcp
8
+ module Resources
9
+ # MCP resource provider for installed hook scripts.
10
+ #
11
+ # Exposes installed rai enforcement hooks as MCP resources
12
+ # with URIs in the format rosett-ai://hooks/{scope}.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class HooksResource
17
+ URI_PREFIX = 'rosett-ai://hooks/'
18
+
19
+ SCOPES = {
20
+ 'global' => -> { RosettAi.paths.global_dir.join('hooks') },
21
+ 'project' => -> { RosettAi.context.project_root.join('.claude', 'hooks') }
22
+ }.freeze
23
+
24
+ # Lists available hook resources.
25
+ #
26
+ # @return [Array<Hash>] resource entries
27
+ def list
28
+ SCOPES.filter_map do |scope, dir_factory|
29
+ dir = safe_dir(dir_factory)
30
+ next unless dir&.directory? && dir.glob('*.rb').any?
31
+
32
+ {
33
+ uri: "#{URI_PREFIX}#{scope}",
34
+ name: "hooks-#{scope}",
35
+ description: "Installed hooks: #{scope} scope",
36
+ mime_type: 'text/x-ruby'
37
+ }
38
+ end
39
+ end
40
+
41
+ # Reads hooks for a specific scope.
42
+ #
43
+ # @param scope [String] 'global' or 'project'
44
+ # @return [Hash, nil] resource content
45
+ def read(scope)
46
+ dir_factory = SCOPES[scope]
47
+ return nil unless dir_factory
48
+
49
+ dir = safe_dir(dir_factory)
50
+ return nil unless dir&.directory?
51
+
52
+ scripts = dir.glob('*.rb').map { |path| File.read(path) }
53
+ return nil if scripts.empty?
54
+
55
+ {
56
+ uri: "#{URI_PREFIX}#{scope}",
57
+ content: scripts.join("\n\n# --- next hook ---\n\n"),
58
+ mime_type: 'text/x-ruby'
59
+ }
60
+ end
61
+
62
+ private
63
+
64
+ # @param factory [Proc]
65
+ # @return [Pathname, nil]
66
+ def safe_dir(factory)
67
+ factory.call
68
+ rescue StandardError
69
+ nil
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end