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,122 @@
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
+ require 'digest'
7
+ require 'pathname'
8
+
9
+ module RosettAi
10
+ module Mcp
11
+ module Tools
12
+ # MCP tool: show compilation staleness status.
13
+ #
14
+ # Compares source behaviour/design YAML files against their compiled
15
+ # output, reporting per-file checksums and staleness. Read-only.
16
+ #
17
+ # @author hugo
18
+ # @author claude
19
+ class CompileStatusTool
20
+ TOOL_NAME = 'rai_compile_status'
21
+ DESCRIPTION = 'Show compiled rules staleness — source vs compiled checksums'
22
+
23
+ ANNOTATIONS = {
24
+ 'readOnlyHint' => true,
25
+ 'destructiveHint' => false,
26
+ 'idempotentHint' => true,
27
+ 'openWorldHint' => false
28
+ }.freeze
29
+
30
+ INPUT_SCHEMA = {
31
+ type: 'object',
32
+ properties: {
33
+ scope: {
34
+ type: 'string',
35
+ description: 'Scope to check staleness for (default: all)'
36
+ }
37
+ }
38
+ }.freeze
39
+
40
+ # Checks staleness of compiled output files.
41
+ #
42
+ # @param scope [String, nil] optional filter ('behaviour', 'design')
43
+ # @return [Hash] per-file staleness report
44
+ def call(scope: nil)
45
+ compiled_dir = RosettAi.paths.rules_dir
46
+ source_dir = resolve_source_dir
47
+
48
+ files = collect_source_files(source_dir, scope)
49
+ report = files.map { |src| build_file_report(src, compiled_dir) }
50
+
51
+ stale_count = report.count { |r| r[:stale] }
52
+ {
53
+ files: report,
54
+ total: report.size,
55
+ stale: stale_count,
56
+ up_to_date: report.size - stale_count,
57
+ compiled_dir: compiled_dir.to_s,
58
+ source_dir: source_dir.to_s
59
+ }
60
+ rescue StandardError => e
61
+ ResponseHelper.error("Compile status failed: #{e.message}")
62
+ end
63
+
64
+ private
65
+
66
+ # @return [Pathname]
67
+ def resolve_source_dir
68
+ return RosettAi.root.join('conf') if RosettAi.context.rai_internal?
69
+
70
+ RosettAi.paths.rai_conf_dir
71
+ end
72
+
73
+ # @param source_dir [Pathname]
74
+ # @param scope [String, nil]
75
+ # @return [Array<Pathname>]
76
+ def collect_source_files(source_dir, scope)
77
+ categories = scope ? [scope] : ['behaviour', 'design']
78
+ categories.flat_map do |cat|
79
+ dir = source_dir.join(cat)
80
+ dir.directory? ? dir.glob('*.yml').sort : []
81
+ end
82
+ end
83
+
84
+ # @param source_path [Pathname]
85
+ # @param compiled_dir [Pathname]
86
+ # @return [Hash]
87
+ def build_file_report(source_path, compiled_dir)
88
+ category = source_path.parent.basename.to_s
89
+ basename = source_path.basename('.yml').to_s
90
+ compiled_name = "#{category}-#{basename}.md"
91
+ compiled_path = compiled_dir.join(compiled_name)
92
+
93
+ source_checksum = file_checksum(source_path)
94
+ compiled_exists = compiled_path.exist?
95
+ compiled_checksum = compiled_exists ? file_checksum(compiled_path) : nil
96
+
97
+ {
98
+ source: source_path.to_s,
99
+ compiled: compiled_path.to_s,
100
+ source_checksum: source_checksum,
101
+ compiled_checksum: compiled_checksum,
102
+ compiled_exists: compiled_exists,
103
+ stale: !compiled_exists || source_newer?(source_path, compiled_path)
104
+ }
105
+ end
106
+
107
+ # @param path [Pathname]
108
+ # @return [String] SHA-256 hex digest
109
+ def file_checksum(path)
110
+ Digest::SHA256.hexdigest(path.read)
111
+ end
112
+
113
+ # @param source [Pathname]
114
+ # @param compiled [Pathname]
115
+ # @return [Boolean]
116
+ def source_newer?(source, compiled)
117
+ source.mtime > compiled.mtime
118
+ end
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,191 @@
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
+ require 'fileutils'
7
+ require 'digest'
8
+
9
+ module RosettAi
10
+ module Mcp
11
+ module Tools
12
+ # MCP tool: compile rai behaviours to engine-native format.
13
+ #
14
+ # Delegates to the real {RosettAi::Compiler::CompilationPipeline}.
15
+ # When simulate=true, returns diffs without writing files.
16
+ # When simulate=false, writes compiled output to disk.
17
+ #
18
+ # @author hugo
19
+ # @author claude
20
+ class CompileTool
21
+ TOOL_NAME = 'rai_compile'
22
+ DESCRIPTION = 'Compile rai behaviours to engine-native format'
23
+
24
+ ANNOTATIONS = {
25
+ 'readOnlyHint' => false,
26
+ 'destructiveHint' => false,
27
+ 'idempotentHint' => true,
28
+ 'openWorldHint' => false
29
+ }.freeze
30
+
31
+ INPUT_SCHEMA = {
32
+ type: 'object',
33
+ properties: {
34
+ simulate: {
35
+ type: 'boolean',
36
+ description: 'Dry-run mode — show what would change without writing (default: true)'
37
+ },
38
+ engine: {
39
+ type: 'string',
40
+ description: 'Target engine format (default: claude)'
41
+ }
42
+ }
43
+ }.freeze
44
+
45
+ # Executes the compilation via the real pipeline.
46
+ #
47
+ # @param simulate [Boolean] dry-run mode (default true)
48
+ # @param engine [String] target engine (default 'claude')
49
+ # @return [Hash] result with compiled file details
50
+ def call(simulate: true, engine: 'claude')
51
+ backend = RosettAi::Compiler::Backend.for(engine)
52
+ pipeline = build_pipeline(backend)
53
+ compiled = pipeline.compile
54
+
55
+ if simulate
56
+ build_simulate_result(pipeline, compiled, engine)
57
+ else
58
+ build_write_result(pipeline, compiled, engine)
59
+ end
60
+ rescue RosettAi::Error => e
61
+ ResponseHelper.error("Compilation failed: #{e.message}")
62
+ end
63
+
64
+ private
65
+
66
+ # @param backend [RosettAi::Compiler::Backend] rendering backend
67
+ # @return [RosettAi::Compiler::CompilationPipeline]
68
+ def build_pipeline(backend)
69
+ scope = detect_scope
70
+ RosettAi::Compiler::CompilationPipeline.new(
71
+ source_dir: resolve_source_dir(scope),
72
+ target_dir: resolve_target_dir(backend, scope),
73
+ schema_dir: RosettAi.root.join('conf', 'schemas'),
74
+ backend: backend,
75
+ scope: scope,
76
+ additional_source_dirs: additional_dirs(scope)
77
+ )
78
+ end
79
+
80
+ # @return [Symbol] :global or :project
81
+ def detect_scope
82
+ ctx = RosettAi.context
83
+ ctx.project? && !ctx.rai_internal? ? :project : :global
84
+ end
85
+
86
+ # @param scope [Symbol]
87
+ # @return [Pathname]
88
+ def resolve_source_dir(scope)
89
+ return RosettAi.root.join('conf') if RosettAi.context.rai_internal?
90
+
91
+ scope == :project ? RosettAi.conf_root.join('conf') : RosettAi.paths.rai_conf_dir
92
+ end
93
+
94
+ # @param backend [RosettAi::Compiler::Backend]
95
+ # @param scope [Symbol]
96
+ # @return [Pathname]
97
+ def resolve_target_dir(backend, scope)
98
+ dir = backend.profile.output_dir
99
+ return Pathname.new(File.expand_path(dir)) if dir
100
+
101
+ return RosettAi.context.project_root.join('.claude', 'rules') if scope == :project
102
+
103
+ RosettAi.paths.rules_dir
104
+ end
105
+
106
+ # @param scope [Symbol]
107
+ # @return [Array<Pathname>]
108
+ def additional_dirs(scope)
109
+ dirs = []
110
+ packaged = RosettAi.paths.packaged_conf_dir
111
+ dirs << packaged if packaged.directory?
112
+ dirs << RosettAi.paths.rai_conf_dir if scope == :project || RosettAi.context.rai_internal?
113
+ dirs
114
+ end
115
+
116
+ # @param pipeline [RosettAi::Compiler::CompilationPipeline]
117
+ # @param compiled [Hash]
118
+ # @param engine [String]
119
+ # @return [Hash]
120
+ def build_simulate_result(pipeline, compiled, engine)
121
+ files = compiled.map do |filename, info|
122
+ target = pipeline.target_dir.join(filename)
123
+ existing = File.exist?(target)
124
+ {
125
+ filename: filename,
126
+ exists: existing,
127
+ stale: existing ? !pipeline.diff(target, info[:content]).nil? : true
128
+ }
129
+ end
130
+
131
+ {
132
+ simulate: true,
133
+ engine: engine,
134
+ status: 'dry-run',
135
+ files: files,
136
+ total: compiled.size,
137
+ message: "Simulation complete — #{compiled.size} file(s), no files written"
138
+ }
139
+ end
140
+
141
+ # @param pipeline [RosettAi::Compiler::CompilationPipeline]
142
+ # @param compiled [Hash]
143
+ # @param engine [String]
144
+ # @return [Hash]
145
+ def build_write_result(pipeline, compiled, engine)
146
+ results = { created: [], updated: [], unchanged: [] }
147
+
148
+ compiled.each do |filename, info|
149
+ target = pipeline.target_dir.join(filename)
150
+ FileUtils.mkdir_p(target.dirname)
151
+ action = write_compiled_file(pipeline, target, info[:content])
152
+ results[action] << filename
153
+ end
154
+
155
+ {
156
+ simulate: false,
157
+ engine: engine,
158
+ status: 'compiled',
159
+ created: results[:created],
160
+ updated: results[:updated],
161
+ unchanged: results[:unchanged],
162
+ total: compiled.size,
163
+ message: "Compilation complete — #{results[:created].size} created, " \
164
+ "#{results[:updated].size} updated, #{results[:unchanged].size} unchanged"
165
+ }
166
+ end
167
+
168
+ # @param pipeline [RosettAi::Compiler::CompilationPipeline]
169
+ # @param target [Pathname]
170
+ # @param content [String]
171
+ # @return [Symbol] :created, :updated, or :unchanged
172
+ def write_compiled_file(pipeline, target, content)
173
+ unless File.exist?(target)
174
+ File.write(target, content)
175
+ return :created
176
+ end
177
+
178
+ existing_checksum = pipeline.checksum(File.read(target, encoding: 'utf-8'))
179
+ new_checksum = pipeline.checksum(content)
180
+
181
+ if existing_checksum == new_checksum
182
+ :unchanged
183
+ else
184
+ File.write(target, content)
185
+ :updated
186
+ end
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,79 @@
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 Tools
9
+ # MCP tool: run rosett-ai compliance checks.
10
+ #
11
+ # Executes CRA, license, and SPDX header checks.
12
+ # Read-only operation — does not modify any files.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class ComplyTool
17
+ TOOL_NAME = 'rai_comply'
18
+ DESCRIPTION = 'Run rosett-ai compliance checks (CRA, license, SPDX headers)'
19
+
20
+ ANNOTATIONS = {
21
+ 'readOnlyHint' => true,
22
+ 'destructiveHint' => false,
23
+ 'idempotentHint' => true,
24
+ 'openWorldHint' => false
25
+ }.freeze
26
+
27
+ INPUT_SCHEMA = {
28
+ type: 'object',
29
+ properties: {
30
+ cra: {
31
+ type: 'boolean',
32
+ description: 'Run CRA-specific checks only (default: false)'
33
+ },
34
+ license: {
35
+ type: 'boolean',
36
+ description: 'Run license audit checks only (default: false)'
37
+ },
38
+ headers: {
39
+ type: 'boolean',
40
+ description: 'Run SPDX header checks only (default: false)'
41
+ },
42
+ format: {
43
+ type: 'string',
44
+ enum: ['json', 'text'],
45
+ description: 'Output format (default: json)'
46
+ }
47
+ }
48
+ }.freeze
49
+
50
+ # Executes compliance checks.
51
+ #
52
+ # @param cra [Boolean] run CRA checks only
53
+ # @param license [Boolean] run license checks only
54
+ # @param headers [Boolean] run SPDX header checks only
55
+ # @param format [String] output format ('json' or 'text')
56
+ # @return [Hash] compliance results
57
+ def call(cra: false, license: false, headers: false, format: 'json')
58
+ checks = filter_checks(cra: cra, license: license, headers: headers)
59
+ results = run_checks(checks)
60
+ violations = results.select { |r| r[:status] == 'fail' }
61
+ { compliant: violations.empty?, results: results, violations: violations, format: format }
62
+ rescue StandardError => e
63
+ ResponseHelper.error("Compliance check failed: #{e.message}")
64
+ end
65
+
66
+ private
67
+
68
+ def filter_checks(cra:, license:, headers:)
69
+ selected = { cra: cra, license: license, headers: headers }.select { |_, v| v }.keys
70
+ selected.empty? ? nil : selected
71
+ end
72
+
73
+ def run_checks(checks)
74
+ RosettAi::Comply::Runner.new(project_root: RosettAi.root, checks: checks).run
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,71 @@
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 Tools
9
+ # MCP tool: compile Claude Code configuration.
10
+ #
11
+ # Compiles YAML scopes to JSON settings files.
12
+ # Requires an engine plugin with config compiler support.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class ConfigCompileTool
17
+ TOOL_NAME = 'rai_config_compile'
18
+ DESCRIPTION = 'Compile rai configuration scopes to JSON settings'
19
+
20
+ ANNOTATIONS = {
21
+ 'readOnlyHint' => false,
22
+ 'destructiveHint' => false,
23
+ 'idempotentHint' => true,
24
+ 'openWorldHint' => false
25
+ }.freeze
26
+
27
+ INPUT_SCHEMA = {
28
+ type: 'object',
29
+ properties: {
30
+ simulate: {
31
+ type: 'boolean',
32
+ description: 'Dry-run mode (default: true)'
33
+ },
34
+ scope: {
35
+ type: 'string',
36
+ description: 'Compile a specific scope only (e.g. managed, user, project)'
37
+ },
38
+ engine: {
39
+ type: 'string',
40
+ description: 'Target engine (default: claude)'
41
+ }
42
+ }
43
+ }.freeze
44
+
45
+ # Executes the configuration compilation.
46
+ #
47
+ # @param simulate [Boolean] dry-run mode
48
+ # @param scope [String, nil] specific scope to compile
49
+ # @param engine [String] target engine
50
+ # @return [Hash] compilation results
51
+ def call(simulate: true, scope: nil, engine: 'claude')
52
+ plugin = RosettAi::Plugins::Registry.plugin_module(:engine, engine)
53
+ compiler_class = plugin&.config_compiler_class
54
+ unless compiler_class
55
+ return ResponseHelper.error(
56
+ "Engine '#{engine}' has no config compiler. " \
57
+ 'Install an engine plugin to enable config compilation.'
58
+ )
59
+ end
60
+
61
+ results = compiler_class.new(simulate: simulate).compile_all(scope: scope)
62
+ { simulate: simulate, scope: scope, engine: engine,
63
+ status: simulate ? 'dry-run' : 'compiled',
64
+ files: results[:files], message: results[:message] }
65
+ rescue StandardError => e
66
+ ResponseHelper.error("Config compile failed: #{e.message}")
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,79 @@
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 Tools
9
+ # MCP tool: show rai configuration status.
10
+ #
11
+ # Returns the current state of rai configuration including
12
+ # project info, engine status, and validation state.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class ConfigStatusTool
17
+ TOOL_NAME = 'rai_config_status'
18
+ DESCRIPTION = 'Show rai configuration and project status'
19
+
20
+ ANNOTATIONS = {
21
+ 'readOnlyHint' => true,
22
+ 'destructiveHint' => false,
23
+ 'idempotentHint' => true,
24
+ 'openWorldHint' => false
25
+ }.freeze
26
+
27
+ # Executes the status check.
28
+ #
29
+ # @return [Hash] result with configuration status
30
+ def call
31
+ {
32
+ version: RosettAi::VERSION,
33
+ project_root: RosettAi.root.to_s,
34
+ behaviours: count_files('conf/behaviour'),
35
+ designs: count_files('conf/design'),
36
+ engines: detect_engines,
37
+ default_engine: detect_default_engine,
38
+ scope: detect_scope
39
+ }
40
+ rescue StandardError => e
41
+ ResponseHelper.error("Config status failed: #{e.message}")
42
+ end
43
+
44
+ private
45
+
46
+ # @param subdir [String]
47
+ # @return [Integer]
48
+ def count_files(subdir)
49
+ dir = RosettAi.root.join(subdir)
50
+ dir.directory? ? dir.glob('*.yml').size : 0
51
+ end
52
+
53
+ # @return [Hash] engine count and any error
54
+ def detect_engines
55
+ registry = RosettAi::Plugins::Registry
56
+ count = registry.respond_to?(:discovered) ? registry.discovered.size : 0
57
+ { count: count }
58
+ rescue StandardError => e
59
+ { count: 0, error: e.message }
60
+ end
61
+
62
+ # @return [String] default engine name or error detail
63
+ def detect_default_engine
64
+ RosettAi.rai_config.default_engine
65
+ rescue StandardError => e
66
+ "unknown (#{e.message})"
67
+ end
68
+
69
+ # @return [String] detected compilation scope
70
+ def detect_scope
71
+ ctx = RosettAi.context
72
+ ctx.project? && !ctx.rai_internal? ? 'project' : 'global'
73
+ rescue StandardError
74
+ 'unknown'
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,78 @@
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 Tools
9
+ # MCP tool: manage content packs.
10
+ #
11
+ # List, install, or update content packs.
12
+ # Write operation for install/update actions.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class ContentTool
17
+ TOOL_NAME = 'rai_content'
18
+ DESCRIPTION = 'List, install, or update rai content packs'
19
+
20
+ ANNOTATIONS = {
21
+ 'readOnlyHint' => false,
22
+ 'destructiveHint' => false,
23
+ 'idempotentHint' => true,
24
+ 'openWorldHint' => true
25
+ }.freeze
26
+
27
+ VALID_ACTIONS = ['list', 'install', 'update'].freeze
28
+
29
+ INPUT_SCHEMA = {
30
+ type: 'object',
31
+ properties: {
32
+ action: {
33
+ type: 'string',
34
+ enum: ['list', 'install', 'update'],
35
+ description: 'Content action (default: list)'
36
+ },
37
+ pack_name: {
38
+ type: 'string',
39
+ description: 'Content pack name (required for install)'
40
+ }
41
+ }
42
+ }.freeze
43
+
44
+ # Executes the content pack operation.
45
+ #
46
+ # @param action [String] one of 'list', 'install', 'update'
47
+ # @param pack_name [String, nil] pack name for install
48
+ # @return [Hash] operation result
49
+ def call(action: 'list', pack_name: nil)
50
+ return ResponseHelper.error("Invalid action: #{action}") unless VALID_ACTIONS.include?(action)
51
+
52
+ case action
53
+ when 'list' then action_list
54
+ when 'install' then action_install(pack_name)
55
+ when 'update' then ResponseHelper.error('Content update requires CLI: raictl content update')
56
+ end
57
+ rescue StandardError => e
58
+ ResponseHelper.error("Content #{action} failed: #{e.message}")
59
+ end
60
+
61
+ private
62
+
63
+ def action_list
64
+ registry = RosettAi::Content::PackRegistry.new
65
+ { packs: registry.installed }
66
+ end
67
+
68
+ def action_install(pack_name)
69
+ return ResponseHelper.error('Pack name required for install') unless pack_name
70
+
71
+ ResponseHelper.error(
72
+ "Content install requires CLI with license key: raictl content install #{pack_name}"
73
+ )
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end