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,173 @@
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 'yaml'
7
+ require 'pathname'
8
+
9
+ module RosettAi
10
+ module Mcp
11
+ module Tools
12
+ # MCP tool: preview a generated enforcement hook script.
13
+ #
14
+ # Generates a Ruby hook script from behaviour rules without writing
15
+ # anything to disk. Allows inspection before installing via
16
+ # {HookInstallTool}. Strictly read-only.
17
+ #
18
+ # Delegates generation to {Enforcement::HookGenerator} and validation
19
+ # to {Enforcement::Validator}.
20
+ #
21
+ # @author hugo
22
+ # @author claude
23
+ class HookPreviewTool
24
+ TOOL_NAME = 'rai_hook_preview'
25
+ DESCRIPTION = 'Preview generated enforcement hook script (read-only, no side effects)'
26
+
27
+ ANNOTATIONS = {
28
+ 'readOnlyHint' => true,
29
+ 'destructiveHint' => false,
30
+ 'idempotentHint' => true,
31
+ 'openWorldHint' => false
32
+ }.freeze
33
+
34
+ INPUT_SCHEMA = {
35
+ type: 'object',
36
+ properties: {
37
+ behaviour_name: {
38
+ type: 'string',
39
+ description: 'Behaviour to preview hook for (default: all enforceable)'
40
+ },
41
+ rule_id: {
42
+ type: 'string',
43
+ description: 'Specific rule ID to preview hook for'
44
+ },
45
+ scope: {
46
+ type: 'string',
47
+ description: 'Preview scope context'
48
+ }
49
+ }
50
+ }.freeze
51
+
52
+ # Generates a preview of the enforcement hook script.
53
+ #
54
+ # @param behaviour_name [String, nil] specific behaviour to generate for
55
+ # @param rule_id [String, nil] specific rule within the behaviour
56
+ # @param scope [String, nil] scope filter ('global', 'project')
57
+ # @return [Hash] generated script content and metadata
58
+ def call(behaviour_name: nil, rule_id: nil, scope: nil)
59
+ behaviours = load_behaviours(behaviour_name, scope)
60
+ validated = validate_and_collect(behaviours, rule_id)
61
+
62
+ return ResponseHelper.error('No enforceable rules found') if validated[:rules].empty?
63
+
64
+ script = generate_script(validated)
65
+ build_response(script, validated, scope)
66
+ rescue StandardError => e
67
+ ResponseHelper.error("Hook preview failed: #{e.message}")
68
+ end
69
+
70
+ private
71
+
72
+ # Loads behaviour files from the appropriate directories.
73
+ #
74
+ # @param behaviour_name [String, nil]
75
+ # @param scope [String, nil]
76
+ # @return [Array<Hash>] loaded behaviour data with metadata
77
+ def load_behaviours(behaviour_name, scope)
78
+ results = []
79
+ each_behaviour_file(scope) do |_path, data|
80
+ next if behaviour_name && data['name'] != behaviour_name
81
+
82
+ results << data
83
+ end
84
+ results
85
+ end
86
+
87
+ # Validates behaviours and collects enforceable rules.
88
+ #
89
+ # @param behaviours [Array<Hash>]
90
+ # @param rule_id [String, nil]
91
+ # @return [Hash] :rules, :downgraded, :behaviour_name, :behaviour_version
92
+ def validate_and_collect(behaviours, rule_id)
93
+ validator = Enforcement::Validator.new
94
+ all_rules = []
95
+ all_downgraded = []
96
+ names = []
97
+
98
+ behaviours.each do |data|
99
+ result = validator.validate(data)
100
+ rules = result[:valid].select { |r| r[:type] == 'enforceable' }
101
+ rules = rules.select { |r| r[:rule_id] == rule_id } if rule_id
102
+ all_rules.concat(rules)
103
+ all_downgraded.concat(result[:downgraded])
104
+ names << data['name']
105
+ end
106
+
107
+ { rules: all_rules, downgraded: all_downgraded,
108
+ behaviour_name: names.join(', '),
109
+ behaviour_version: behaviours.first&.fetch('version', '0.0.0') || '0.0.0' }
110
+ end
111
+
112
+ # Generates the hook script via HookGenerator.
113
+ #
114
+ # @param validated [Hash]
115
+ # @return [String]
116
+ def generate_script(validated)
117
+ generator = Enforcement::HookGenerator.new
118
+ generator.generate(
119
+ validated[:rules],
120
+ behaviour_name: validated[:behaviour_name],
121
+ behaviour_version: validated[:behaviour_version]
122
+ )
123
+ end
124
+
125
+ # @param script [String]
126
+ # @param validated [Hash]
127
+ # @param scope [String, nil]
128
+ # @return [Hash]
129
+ def build_response(script, validated, scope)
130
+ response = {
131
+ script: script,
132
+ rules_count: validated[:rules].size,
133
+ behaviours: validated[:rules].map { |r| r[:behaviour] }.uniq,
134
+ scope: scope || 'global',
135
+ preview_only: true
136
+ }
137
+ response[:downgraded] = validated[:downgraded] unless validated[:downgraded].empty?
138
+ response
139
+ end
140
+
141
+ # @param scope [String, nil]
142
+ # @yield [Pathname, Hash]
143
+ def each_behaviour_file(scope)
144
+ dirs = behaviour_dirs(scope)
145
+ dirs.each do |dir|
146
+ next unless dir.directory?
147
+
148
+ dir.glob('*.yml').each do |path|
149
+ data = YAML.safe_load_file(path, permitted_classes: [Symbol])
150
+ yield path, data if data.is_a?(Hash)
151
+ rescue Psych::Exception
152
+ next
153
+ end
154
+ end
155
+ end
156
+
157
+ # @param scope [String, nil]
158
+ # @return [Array<Pathname>]
159
+ def behaviour_dirs(scope)
160
+ case scope
161
+ when 'project'
162
+ [RosettAi.conf_root.join('conf', 'behaviour')]
163
+ else
164
+ dirs = [RosettAi.root.join('conf', 'behaviour')]
165
+ xdg = RosettAi.paths.rai_conf_dir.join('behaviour')
166
+ dirs << xdg if xdg.directory?
167
+ dirs
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,84 @@
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 git hooks status.
10
+ #
11
+ # Lists configured hooks and their installation status.
12
+ # Read-only operation.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class HooksStatusTool
17
+ TOOL_NAME = 'rai_hooks_status'
18
+ DESCRIPTION = 'Show git hooks list and installation status'
19
+
20
+ ANNOTATIONS = {
21
+ 'readOnlyHint' => true,
22
+ 'destructiveHint' => false,
23
+ 'idempotentHint' => true,
24
+ 'openWorldHint' => false
25
+ }.freeze
26
+
27
+ VALID_ACTIONS = ['list', 'status'].freeze
28
+
29
+ INPUT_SCHEMA = {
30
+ type: 'object',
31
+ properties: {
32
+ action: {
33
+ type: 'string',
34
+ enum: ['list', 'status'],
35
+ description: 'Hooks action (default: status)'
36
+ }
37
+ }
38
+ }.freeze
39
+
40
+ # Known overcommit hook phases.
41
+ HOOK_PHASES = [
42
+ 'PreCommit', 'CommitMsg', 'PrePush', 'PreRebase',
43
+ 'PostCheckout', 'PostCommit', 'PostMerge', 'PostRewrite'
44
+ ].freeze
45
+
46
+ # Executes the hooks query.
47
+ #
48
+ # @param action [String] one of 'list' or 'status'
49
+ # @return [Hash] hooks information
50
+ def call(action: 'status')
51
+ return ResponseHelper.error("Invalid action: #{action}") unless VALID_ACTIONS.include?(action)
52
+
53
+ hooks_config = RosettAi.root.join('.overcommit.yml')
54
+ return ResponseHelper.error('No .overcommit.yml found') unless hooks_config.exist?
55
+
56
+ data = YAML.safe_load_file(hooks_config, permitted_classes: [Symbol])
57
+ {
58
+ action: action,
59
+ installed: RosettAi.root.join('.git', 'hooks', 'overcommit-hook').exist?,
60
+ hooks: extract_hooks(data)
61
+ }
62
+ rescue Psych::SyntaxError => e
63
+ ResponseHelper.error("Hooks config parse error: #{e.message}")
64
+ end
65
+
66
+ private
67
+
68
+ # Extracts hook configuration for all overcommit phases.
69
+ #
70
+ # @param data [Hash] parsed .overcommit.yml content
71
+ # @return [Hash{String => Array<String>}] phase to hook names
72
+ def extract_hooks(data)
73
+ return {} unless data.is_a?(Hash)
74
+
75
+ data.each_with_object({}) do |(phase, hooks), result|
76
+ next unless hooks.is_a?(Hash) && HOOK_PHASES.include?(phase)
77
+
78
+ result[phase] = hooks.keys.reject { |k| k == 'ALL' }
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,87 @@
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: initialize rosett-ai structure.
10
+ #
11
+ # Sets up global, local, or project directory structure.
12
+ # Write operation — creates directories and files.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class InitTool
17
+ TOOL_NAME = 'rai_init'
18
+ DESCRIPTION = 'Initialize rosett-ai directory structure (global, local, or project)'
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
+ global: {
31
+ type: 'boolean',
32
+ description: 'Initialize global ~/.claude/ structure (default: false)'
33
+ },
34
+ local: {
35
+ type: 'boolean',
36
+ description: 'Initialize project-local .claude/ structure (default: false)'
37
+ },
38
+ project: {
39
+ type: 'boolean',
40
+ description: 'Initialize .rosett-ai/ project structure (default: false)'
41
+ }
42
+ }
43
+ }.freeze
44
+
45
+ # Executes the initialization.
46
+ #
47
+ # @param global [Boolean] set up global structure
48
+ # @param local [Boolean] set up project-local structure
49
+ # @param project [Boolean] set up .rosett-ai/ project structure
50
+ # @return [Hash] initialization results
51
+ def call(global: false, local: false, project: false)
52
+ unless global || local || project
53
+ return ResponseHelper.error('At least one scope required: global, local, or project')
54
+ end
55
+
56
+ results = { scopes: [], created: [] }
57
+ init_global(results) if global
58
+ init_local(results) if local
59
+ init_project(results) if project
60
+ ResponseHelper.success('Initialization complete', results)
61
+ rescue StandardError => e
62
+ ResponseHelper.error("Init failed: #{e.message}")
63
+ end
64
+
65
+ private
66
+
67
+ def init_global(results)
68
+ initializer = RosettAi::Init::GlobalInitializer.new
69
+ initializer.setup
70
+ results[:scopes] << 'global'
71
+ end
72
+
73
+ def init_local(results)
74
+ initializer = RosettAi::Init::LocalInitializer.new
75
+ initializer.setup
76
+ results[:scopes] << 'local'
77
+ end
78
+
79
+ def init_project(results)
80
+ initializer = RosettAi::Init::ProjectInitializer.new
81
+ initializer.setup
82
+ results[:scopes] << 'project'
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,44 @@
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 license status.
10
+ #
11
+ # Returns the current license activation status.
12
+ # Read-only operation.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class LicenseStatusTool
17
+ TOOL_NAME = 'rai_license_status'
18
+ DESCRIPTION = 'Show rai license activation status'
19
+
20
+ ANNOTATIONS = {
21
+ 'readOnlyHint' => true,
22
+ 'destructiveHint' => false,
23
+ 'idempotentHint' => true,
24
+ 'openWorldHint' => false
25
+ }.freeze
26
+
27
+ # Executes the license status check.
28
+ #
29
+ # @return [Hash] license status information
30
+ def call
31
+ result = RosettAi::Licensing::LicenseValidator.new.validate
32
+ {
33
+ active: result[:valid],
34
+ tier: result[:tier]&.to_s,
35
+ key_present: result[:key_present],
36
+ message: result[:message]
37
+ }
38
+ rescue StandardError => e
39
+ ResponseHelper.error("License check failed: #{e.message}")
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,117 @@
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 project status and information.
10
+ #
11
+ # Returns project lifecycle status, info, or drift detection.
12
+ # Read-only operation.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class ProjectTool
17
+ TOOL_NAME = 'rai_project'
18
+ DESCRIPTION = 'Show rai project status, info, or drift detection'
19
+
20
+ ANNOTATIONS = {
21
+ 'readOnlyHint' => true,
22
+ 'destructiveHint' => false,
23
+ 'idempotentHint' => true,
24
+ 'openWorldHint' => false
25
+ }.freeze
26
+
27
+ VALID_ACTIONS = ['status', 'info', 'drift'].freeze
28
+
29
+ INPUT_SCHEMA = {
30
+ type: 'object',
31
+ properties: {
32
+ action: {
33
+ type: 'string',
34
+ enum: ['status', 'info', 'drift'],
35
+ description: 'Project action (default: status)'
36
+ }
37
+ }
38
+ }.freeze
39
+
40
+ # Executes the project query.
41
+ #
42
+ # @param action [String] one of 'status', 'info', 'drift'
43
+ # @return [Hash] project information
44
+ def call(action: 'status')
45
+ return ResponseHelper.error("Invalid action: #{action}") unless VALID_ACTIONS.include?(action)
46
+
47
+ case action
48
+ when 'status' then action_status
49
+ when 'info' then action_info
50
+ when 'drift' then action_drift
51
+ end
52
+ rescue StandardError => e
53
+ ResponseHelper.error("Project #{action} failed: #{e.message}")
54
+ end
55
+
56
+ private
57
+
58
+ def action_status
59
+ {
60
+ project_root: RosettAi.root.to_s,
61
+ version: RosettAi::VERSION,
62
+ behaviours: count_files('conf/behaviour'),
63
+ designs: count_files('conf/design'),
64
+ engines: detect_engines
65
+ }
66
+ end
67
+
68
+ def action_info
69
+ spec = load_gemspec
70
+ {
71
+ name: spec&.name || 'rosett-ai',
72
+ summary: spec&.summary || 'Unknown',
73
+ version: RosettAi::VERSION,
74
+ license: spec&.license || 'Unknown',
75
+ authors: spec&.authors || [],
76
+ homepage: spec&.homepage || 'Unknown',
77
+ ruby_version: RUBY_VERSION,
78
+ required_ruby: spec&.required_ruby_version&.to_s || 'Unknown',
79
+ project_root: RosettAi.root.to_s
80
+ }
81
+ end
82
+
83
+ def action_drift
84
+ compiled_dir = Pathname.new(File.expand_path('~/.claude/rules'))
85
+ {
86
+ compiled_rules_exist: compiled_dir.directory?,
87
+ compiled_count: compiled_dir.directory? ? compiled_dir.glob('*.md').size : 0,
88
+ source_count: count_files('conf/behaviour') + count_files('conf/design')
89
+ }
90
+ end
91
+
92
+ def count_files(subdir)
93
+ dir = RosettAi.root.join(subdir)
94
+ dir.directory? ? dir.glob('*.yml').size : 0
95
+ end
96
+
97
+ def detect_engines
98
+ RosettAi::Plugins::Registry.available(:engine).size
99
+ rescue StandardError
100
+ 0
101
+ end
102
+
103
+ # Loads the gemspec from the project root.
104
+ #
105
+ # @return [Gem::Specification, nil]
106
+ def load_gemspec
107
+ gemspec = RosettAi.root.glob('*.gemspec').first
108
+ return nil unless gemspec&.exist?
109
+
110
+ Gem::Specification.load(gemspec.to_s)
111
+ rescue StandardError
112
+ nil
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,97 @@
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: query AI provenance information.
10
+ #
11
+ # Validates, shows, and logs provenance entries.
12
+ # Read-only operation.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class ProvenanceTool
17
+ TOOL_NAME = 'rai_provenance'
18
+ DESCRIPTION = 'Query AI provenance (validate, show, log)'
19
+
20
+ ANNOTATIONS = {
21
+ 'readOnlyHint' => true,
22
+ 'destructiveHint' => false,
23
+ 'idempotentHint' => true,
24
+ 'openWorldHint' => false
25
+ }.freeze
26
+
27
+ VALID_ACTIONS = ['validate', 'show', 'log'].freeze
28
+
29
+ INPUT_SCHEMA = {
30
+ type: 'object',
31
+ properties: {
32
+ action: {
33
+ type: 'string',
34
+ enum: ['validate', 'show', 'log'],
35
+ description: 'Provenance action (default: log)'
36
+ },
37
+ commit: {
38
+ type: 'string',
39
+ description: 'Commit SHA to show provenance for (for show action)'
40
+ },
41
+ file: {
42
+ type: 'string',
43
+ description: 'File path to show provenance for (for show action)'
44
+ },
45
+ role: {
46
+ type: 'string',
47
+ description: 'Filter by AI role (for log action)'
48
+ }
49
+ }
50
+ }.freeze
51
+
52
+ # Executes the provenance query.
53
+ #
54
+ # @param action [String] one of 'validate', 'show', 'log'
55
+ # @param commit [String, nil] commit SHA for show action
56
+ # @param file [String, nil] file path filter
57
+ # @param role [String, nil] AI role filter for log
58
+ # @return [Hash] provenance information
59
+ def call(action: 'log', commit: nil, file: nil, role: nil)
60
+ return ResponseHelper.error("Invalid action: #{action}") unless VALID_ACTIONS.include?(action)
61
+
62
+ tracker = RosettAi::Provenance::Tracker.new
63
+ case action
64
+ when 'validate' then action_validate(tracker)
65
+ when 'show' then action_show(tracker, commit: commit, file: file)
66
+ when 'log' then action_log(tracker, role: role)
67
+ end
68
+ rescue StandardError => e
69
+ ResponseHelper.error("Provenance #{action} failed: #{e.message}")
70
+ end
71
+
72
+ private
73
+
74
+ def action_validate(tracker)
75
+ results = tracker.validate
76
+ { valid: results[:errors].empty?, errors: results[:errors] }
77
+ end
78
+
79
+ def action_show(tracker, commit:, file:)
80
+ entries = if commit
81
+ [tracker.find_by_commit(commit)].compact
82
+ elsif file
83
+ tracker.find_by_file(file)
84
+ else
85
+ return ResponseHelper.error('Either commit or file is required for show')
86
+ end
87
+ { entries: entries }
88
+ end
89
+
90
+ def action_log(tracker, role:)
91
+ entries = tracker.log(role: role)
92
+ { entries: entries, total: entries.size }
93
+ end
94
+ end
95
+ end
96
+ end
97
+ 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 Tools
9
+ # MCP tool: initialize provenance tracking.
10
+ #
11
+ # Creates .ai-provenance.yml in the project root.
12
+ # Write operation — creates a new file.
13
+ #
14
+ # @author hugo
15
+ # @author claude
16
+ class ProvenanceWriteTool
17
+ TOOL_NAME = 'rai_provenance_init'
18
+ DESCRIPTION = 'Initialize AI provenance tracking in a project'
19
+
20
+ ANNOTATIONS = {
21
+ 'readOnlyHint' => false,
22
+ 'destructiveHint' => false,
23
+ 'idempotentHint' => true,
24
+ 'openWorldHint' => false
25
+ }.freeze
26
+
27
+ # Executes the provenance initialization.
28
+ #
29
+ # @return [Hash] initialization result
30
+ def call
31
+ store = RosettAi::Provenance::Store.new(root: Dir.pwd)
32
+ store.init
33
+ ResponseHelper.success('Provenance tracking initialized', path: store.path.to_s)
34
+ rescue StandardError => e
35
+ ResponseHelper.error("Provenance init failed: #{e.message}")
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end