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,92 @@
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 'json'
7
+ require 'json_schemer'
8
+
9
+ module RosettAi
10
+ module Packaging
11
+ # Loads and validates packaging variant configs from conf/packaging/<name>.yml.
12
+ #
13
+ # Each variant declares a Debian package with its metadata, system
14
+ # dependencies, and package dependencies. The special version keyword
15
+ # "current" resolves to ">= #{RosettAi::VERSION}" at load time, ensuring
16
+ # atomic version updates per lifecycle_management.yml constraints.
17
+ class VariantConfig
18
+ FIELDS = [
19
+ :name, :variant, :description, :ui_adapter,
20
+ :system_dependencies, :package_dependencies
21
+ ].freeze
22
+
23
+ attr_reader(*FIELDS)
24
+
25
+ def initialize(data)
26
+ FIELDS.each do |field|
27
+ instance_variable_set(:"@#{field}", data[field.to_s])
28
+ end
29
+ @system_dependencies ||= []
30
+ @package_dependencies ||= []
31
+ end
32
+
33
+ def self.load(variant_name)
34
+ path = variants_dir.join("#{variant_name}.yml")
35
+ unless path.exist?
36
+ raise RosettAi::ConfigurationError,
37
+ "Unknown variant: #{variant_name}. Available: #{available.join(', ')}"
38
+ end
39
+
40
+ data = RosettAi::YamlLoader.load_file(path)
41
+ validate!(data, path)
42
+ new(data)
43
+ end
44
+
45
+ def self.available
46
+ Dir.glob(variants_dir.join('*.yml')).map do |file|
47
+ File.basename(file, '.yml')
48
+ end.sort
49
+ end
50
+
51
+ def self.variants_dir
52
+ RosettAi.root.join('conf', 'packaging')
53
+ end
54
+
55
+ def fpm_depends
56
+ deps = system_dependencies.dup
57
+ package_dependencies.each do |dep|
58
+ version = resolve_version(dep['version'])
59
+ deps << "#{dep['name']} (#{version})"
60
+ end
61
+ deps
62
+ end
63
+
64
+ def depends_on_core?
65
+ package_dependencies.any? { |dep| dep['name'] == 'rosett-ai' }
66
+ end
67
+
68
+ def self.validate!(data, path)
69
+ schema_path = RosettAi.root.join('conf', 'schemas', 'packaging_schema.json')
70
+ schema = JSON.parse(schema_path.read)
71
+ schemer = JSONSchemer.schema(schema)
72
+ errors = schemer.validate(data).to_a
73
+ return if errors.empty?
74
+
75
+ messages = errors.map do |err|
76
+ pointer = err['data_pointer'].empty? ? 'root' : err['data_pointer']
77
+ "#{pointer}: #{err['type']}"
78
+ end
79
+ raise RosettAi::ConfigurationError, "Invalid variant config #{path}: #{messages.join(', ')}"
80
+ end
81
+ private_class_method :validate!
82
+
83
+ private
84
+
85
+ def resolve_version(constraint)
86
+ return ">= #{RosettAi::VERSION}" if constraint == 'current'
87
+
88
+ constraint
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+ # AI-Co-Author: Claude Opus 4.6 (Anthropic) <noreply@anthropic.com>
6
+
7
+ module RosettAi
8
+ # Resolves filesystem paths for rai configuration directories.
9
+ # Uses instance methods for future multi-engine support (ADR-006).
10
+ class PathResolver
11
+ attr_reader :engine
12
+
13
+ # Create a new path resolver for the given engine.
14
+ #
15
+ # @param engine [Symbol] engine name
16
+ # @return [PathResolver]
17
+ def initialize(engine: :claude)
18
+ @engine = engine
19
+ end
20
+
21
+ # Engine-specific paths (upstream convention)
22
+
23
+ # Global configuration directory.
24
+ # @return [Pathname] ~/.claude/
25
+ def global_dir = Pathname.new(File.expand_path('~/.claude'))
26
+
27
+ # Compiled rules output directory.
28
+ # @return [Pathname] ~/.claude/rules/
29
+ def rules_dir = global_dir.join('rules')
30
+
31
+ # Project-local configuration directory.
32
+ # @return [Pathname] .claude/ in the user's working directory
33
+ def local_dir = Pathname.new(user_pwd).join('.claude')
34
+
35
+ # Project-level CLAUDE.md file.
36
+ # @return [Pathname] CLAUDE.md in the user's working directory
37
+ def project_claude_md = Pathname.new(user_pwd).join('CLAUDE.md')
38
+
39
+ # Rosett-AI domain (XDG-compliant)
40
+
41
+ # XDG-compliant rai configuration directory.
42
+ # @return [Pathname] $XDG_CONFIG_HOME/rosett-ai or ~/.config/rosett-ai
43
+ def rai_config_dir
44
+ xdg = ENV.fetch('XDG_CONFIG_HOME', File.join(Dir.home, '.config'))
45
+ Pathname.new(xdg).join('rosett-ai')
46
+ end
47
+
48
+ # XDG-compliant rai behaviour/design conf directory.
49
+ # This is where user-level behaviours live — the global compile source.
50
+ # @return [Pathname] $XDG_CONFIG_HOME/rosett-ai/conf or ~/.config/rosett-ai/conf
51
+ def rai_conf_dir = rai_config_dir.join('conf')
52
+
53
+ # Packaged defaults directory (from .deb install).
54
+ # @return [Pathname] /opt/rosett-ai/app/conf
55
+ def packaged_conf_dir = Pathname.new('/opt/rosett-ai/app/conf')
56
+
57
+ # Encrypted secrets store.
58
+ # @return [Pathname] secrets.yml inside the rosett-ai config directory
59
+ def secrets_file = rai_config_dir.join('secrets.yml')
60
+
61
+ # Ed25519-signed JWT license key file.
62
+ # @return [Pathname] license.key inside the rosett-ai config directory
63
+ def license_file = rai_config_dir.join('license.key')
64
+
65
+ # Premium content packs directory.
66
+ # @return [Pathname] premium/ inside the rosett-ai config directory
67
+ def premium_content_dir = rai_config_dir.join('premium')
68
+
69
+ # Content pack cache directory.
70
+ # @return [Pathname] cache/content/ inside the rosett-ai config directory
71
+ def content_cache_dir = rai_config_dir.join('cache', 'content')
72
+
73
+ # Engine settings target paths
74
+
75
+ # System-wide managed settings (enterprise).
76
+ # @return [Pathname] /etc/claude-code/managed-settings.json
77
+ def managed_settings_path
78
+ Pathname.new('/etc/claude-code/managed-settings.json')
79
+ end
80
+
81
+ # Global user settings file.
82
+ # @return [Pathname] settings.json inside ~/.claude/
83
+ def user_settings_path = global_dir.join('settings.json')
84
+
85
+ # Project-level settings file.
86
+ # @return [Pathname] settings.json inside .claude/
87
+ def project_settings_path = local_dir.join('settings.json')
88
+
89
+ # Local settings override (gitignored).
90
+ # @return [Pathname] settings.local.json inside .claude/
91
+ def local_settings_path = local_dir.join('settings.local.json')
92
+
93
+ # Claude engine configuration source directory.
94
+ # @return [Pathname] conf/engines/claude/config/ relative to Rosett-AI root
95
+ def claude_code_config_dir = RosettAi.root.join('conf', 'engines', 'claude', 'config')
96
+
97
+ # Tilde-form display path for lockfile output.
98
+ # @return [String] ~/.claude/rules
99
+ def rules_display_path = '~/.claude/rules'
100
+
101
+ # The user's original working directory.
102
+ # When running from the .deb wrapper, Dir.pwd is /opt/rosett-ai/app, so
103
+ # RAI_ORIGINAL_PWD (set by the wrapper) preserves the real directory.
104
+ # @return [String] user's working directory
105
+ def user_pwd
106
+ ENV.fetch('RAI_ORIGINAL_PWD', Dir.pwd)
107
+ end
108
+
109
+ # Memoized default instance for single-engine usage.
110
+ # @return [PathResolver] instance with engine set to :claude
111
+ def self.default
112
+ @default ||= new
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,43 @@
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 Plugins
8
+ # Base contract module shared by all plugin types (engines, GUIs, MCPs).
9
+ #
10
+ # Every Rosett-AI plugin gem must include this module (or a type-specific
11
+ # subcontract that itself includes Contract) and implement the required
12
+ # class methods. The registry uses these methods for discovery,
13
+ # display, and version negotiation.
14
+ module Contract
15
+ def self.included(base)
16
+ base.extend(ClassMethods)
17
+ end
18
+
19
+ # Class-level interface that every plugin must implement.
20
+ module ClassMethods
21
+ # @return [Symbol] one of :engine, :gui, :mcp
22
+ def plugin_type
23
+ raise NotImplementedError, "#{self}#plugin_type must return :engine, :gui, or :mcp"
24
+ end
25
+
26
+ # @return [String] machine-readable plugin name (e.g. 'claude', 'gtk4')
27
+ def plugin_name
28
+ raise NotImplementedError, "#{self}#plugin_name must return the plugin identifier"
29
+ end
30
+
31
+ # @return [String] human-readable display name (e.g. 'ACME AI Tool (Example)')
32
+ def display_name
33
+ raise NotImplementedError, "#{self}#display_name must return a human-readable name"
34
+ end
35
+
36
+ # @return [String] SemVer version string
37
+ def version
38
+ raise NotImplementedError, "#{self}#version must return a SemVer string"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,60 @@
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 Plugins
8
+ # Contract module for engine plugins.
9
+ #
10
+ # Engine plugins compile behaviour YAML into tool-specific formats,
11
+ # detect installed AI tools, execute API calls, and compile
12
+ # tool-native configuration.
13
+ #
14
+ # Include this module in your engine's registration module and
15
+ # implement all required class methods.
16
+ module EngineContract
17
+ def self.included(base)
18
+ base.include(Contract)
19
+ base.extend(ClassMethods)
20
+ end
21
+
22
+ # Engine-specific class methods beyond the base Contract.
23
+ module ClassMethods
24
+ def plugin_type = :engine
25
+
26
+ # @return [String] engine identifier (e.g. 'claude', 'goose')
27
+ def engine_name
28
+ raise NotImplementedError, "#{self}#engine_name must return the engine identifier"
29
+ end
30
+
31
+ # @return [Class] the Backend subclass for rule compilation
32
+ def backend_class
33
+ raise NotImplementedError, "#{self}#backend_class must return the backend class"
34
+ end
35
+
36
+ # @return [Class, nil] optional Detector subclass for system probing
37
+ def detector_class = nil
38
+
39
+ # @return [Class, nil] optional Executor subclass for API calls
40
+ def executor_class = nil
41
+
42
+ # @return [Class, nil] optional ConfigCompiler subclass for settings compilation
43
+ def config_compiler_class = nil
44
+
45
+ # @return [Pathname] path to the engine's manifest.yml
46
+ def manifest_path
47
+ raise NotImplementedError, "#{self}#manifest_path must return the manifest path"
48
+ end
49
+
50
+ # @return [Pathname] path to the engine's target profile YAML
51
+ def target_profile_path
52
+ manifest_path.dirname.join('target.yml')
53
+ end
54
+
55
+ # Convenience alias — delegates to plugin_name for Contract compatibility.
56
+ def plugin_name = engine_name
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ module RosettAi
7
+ module Plugins
8
+ # Contract module for GUI plugins.
9
+ #
10
+ # GUI plugins provide desktop interfaces (GTK4, Qt6, etc.) that
11
+ # communicate with Rosett-AI core via D-Bus IPC.
12
+ #
13
+ # Include this module in your GUI's registration module and
14
+ # implement all required class methods.
15
+ #
16
+ # @author hugo
17
+ # @author claude
18
+ module GuiContract
19
+ def self.included(base)
20
+ base.include(Contract)
21
+ base.extend(ClassMethods)
22
+ end
23
+
24
+ # GUI-specific class methods beyond the base Contract.
25
+ module ClassMethods
26
+ def plugin_type = :gui
27
+
28
+ # @return [String] GUI identifier (e.g. 'gtk4', 'qt6')
29
+ def gui_name
30
+ raise NotImplementedError, "#{self}#gui_name must return the GUI identifier"
31
+ end
32
+
33
+ # @return [Symbol] toolkit identifier (:gtk4, :qt6, etc.)
34
+ def toolkit
35
+ raise NotImplementedError, "#{self}#toolkit must return a toolkit symbol"
36
+ end
37
+
38
+ # @return [Class] the main application class
39
+ def application_class
40
+ raise NotImplementedError, "#{self}#application_class must return the application class"
41
+ end
42
+
43
+ # Check if system dependencies for this GUI are available.
44
+ #
45
+ # @return [Boolean]
46
+ def available?
47
+ false
48
+ end
49
+
50
+ # Launch the GUI application.
51
+ #
52
+ # @param argv [Array<String>] command-line arguments
53
+ # @return [Integer] exit code
54
+ def launch(argv)
55
+ app = application_class.new
56
+ app.run(argv)
57
+ end
58
+
59
+ # List system packages required by this GUI.
60
+ #
61
+ # @return [Array<String>] package names (e.g. ['libgtk-4-1'])
62
+ def required_system_packages
63
+ []
64
+ end
65
+
66
+ # @return [Class, nil] optional D-Bus interface class
67
+ def dbus_interface_class = nil
68
+
69
+ # Convenience alias — delegates to plugin_name for Contract compatibility.
70
+ def plugin_name = gui_name
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,48 @@
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 Plugins
8
+ # Contract module for MCP (Model Context Protocol) plugins.
9
+ #
10
+ # MCP plugins expose rosett-ai functionality as MCP servers with
11
+ # tool and resource definitions.
12
+ #
13
+ # Include this module in your MCP's registration module and
14
+ # implement all required class methods.
15
+ module McpContract
16
+ def self.included(base)
17
+ base.include(Contract)
18
+ base.extend(ClassMethods)
19
+ end
20
+
21
+ # MCP-specific class methods beyond the base Contract.
22
+ module ClassMethods
23
+ def plugin_type = :mcp
24
+
25
+ # @return [String] MCP server identifier (e.g. 'server')
26
+ def mcp_name
27
+ raise NotImplementedError, "#{self}#mcp_name must return the MCP identifier"
28
+ end
29
+
30
+ # @return [Class] the MCP server class
31
+ def server_class
32
+ raise NotImplementedError, "#{self}#server_class must return the server class"
33
+ end
34
+
35
+ # @return [Array<Hash>] MCP tool schema definitions
36
+ def tool_definitions
37
+ raise NotImplementedError, "#{self}#tool_definitions must return tool schemas"
38
+ end
39
+
40
+ # @return [Array<Hash>] MCP resource definitions (optional)
41
+ def resource_definitions = []
42
+
43
+ # Convenience alias — delegates to plugin_name for Contract compatibility.
44
+ def plugin_name = mcp_name
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,150 @@
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 Plugins
8
+ # Dynamic, multi-type plugin registry.
9
+ #
10
+ # Plugins self-register via `RosettAi::Plugins::Registry.register(:engine, 'claude', MyModule)`.
11
+ # External plugin gems are discovered via `Gem.find_files` — install a gem,
12
+ # and it becomes available automatically.
13
+ #
14
+ # Replaces the hardcoded ENGINES and BACKENDS maps from
15
+ # RosettAi::Engines::Registry and RosettAi::Compiler::Backend.
16
+ class Registry
17
+ PLUGIN_TYPES = [:engine, :gui, :mcp].freeze
18
+
19
+ class PluginNotFoundError < RosettAi::Error; end
20
+
21
+ @plugins = Hash.new { |h, k| h[k] = {} }
22
+ @discovered = false
23
+
24
+ class << self
25
+ # Register a plugin module under a type and name.
26
+ #
27
+ # @param type [Symbol] one of :engine, :gui, :mcp
28
+ # @param name [String, Symbol] plugin identifier
29
+ # @param plugin_module [Module] the module including the appropriate contract
30
+ def register(type, name, plugin_module)
31
+ validate_type!(type)
32
+ @plugins[type][name.to_s] = plugin_module
33
+ end
34
+
35
+ # @param type [Symbol] plugin type
36
+ # @return [Array<String>] sorted list of registered plugin names
37
+ def available(type)
38
+ validate_type!(type)
39
+ @plugins[type].keys.sort
40
+ end
41
+
42
+ # @param type [Symbol] plugin type
43
+ # @param name [String, Symbol] plugin identifier
44
+ # @return [Module] the registered plugin module
45
+ # @raise [PluginNotFoundError] if not found
46
+ def plugin_module(type, name)
47
+ validate_type!(type)
48
+ @plugins[type].fetch(name.to_s) do
49
+ raise PluginNotFoundError,
50
+ "Unknown #{type} plugin: #{name}. Available: #{available(type).join(', ')}"
51
+ end
52
+ end
53
+
54
+ # @param type [Symbol] plugin type
55
+ # @param name [String, Symbol] plugin identifier
56
+ # @return [Boolean]
57
+ def registered?(type, name)
58
+ validate_type!(type)
59
+ @plugins[type].key?(name.to_s)
60
+ end
61
+
62
+ # Convenience accessors for each plugin type.
63
+ def engines = @plugins[:engine]
64
+ def guis = @plugins[:gui]
65
+ def mcps = @plugins[:mcp]
66
+
67
+ # Discover and load all installed plugin gems.
68
+ #
69
+ # Scans for `rosett_ai_engine/*/register.rb`, `rosett_ai_gui/*/register.rb`,
70
+ # and `rosett_ai_mcp/*/register.rb` across all gem load paths.
71
+ # Each register.rb is expected to call `Registry.register`.
72
+ def discover!
73
+ return if @discovered
74
+
75
+ discover_type('rosett_ai_engine')
76
+ discover_type('rosett_ai_gui')
77
+ discover_type('rosett_ai_mcp')
78
+ @discovered = true
79
+ end
80
+
81
+ # Reset the registry. Intended for testing only.
82
+ def reset!
83
+ @plugins = Hash.new { |h, k| h[k] = {} }
84
+ @discovered = false
85
+ end
86
+
87
+ private
88
+
89
+ def validate_type!(type)
90
+ return if PLUGIN_TYPES.include?(type)
91
+
92
+ raise ArgumentError, "Invalid plugin type: #{type}. Valid: #{PLUGIN_TYPES.join(', ')}"
93
+ end
94
+
95
+ def discover_type(prefix)
96
+ # 1. Standard gem discovery (works when GEM_PATH matches Ruby ABI)
97
+ Gem.find_files("#{prefix}/*/register.rb").each do |path|
98
+ require path
99
+ rescue LoadError => e
100
+ RosettAi.logger.warn("Failed to load plugin from #{path}: #{e.message}")
101
+ end
102
+
103
+ # 2. Fallback: version-agnostic scan of embedded gem tree
104
+ # Covers Ruby ABI mismatch between embedded Ruby and engine gems
105
+ discover_embedded_gems(prefix)
106
+
107
+ # 3. Custom engine path (dev/testing via RAI_ENGINE_PATH)
108
+ discover_custom_path(prefix)
109
+ end
110
+
111
+ # Scan `/opt/rosett-ai/embedded/lib/ruby/gems/*/gems/*/lib/` for plugin
112
+ # register.rb files. Handles Ruby ABI version mismatches between
113
+ # the embedded Ruby and engine gems built with a different minor version.
114
+ #
115
+ # @param prefix [String] plugin namespace prefix (e.g. 'rosett_ai_engine')
116
+ def discover_embedded_gems(prefix)
117
+ embedded_gems = Pathname.new('/opt/rosett-ai/embedded/lib/ruby/gems')
118
+ return unless embedded_gems.directory?
119
+
120
+ Dir.glob(embedded_gems.join('*', 'gems', '*', 'lib', prefix, '*', 'register.rb').to_s).each do |path|
121
+ lib_dir = File.expand_path('../../..', path)
122
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
123
+ require path
124
+ rescue LoadError => e
125
+ RosettAi.logger.warn("Failed to load embedded plugin from #{path}: #{e.message}")
126
+ end
127
+ end
128
+
129
+ # Scan directories listed in `RAI_ENGINE_PATH` (colon-separated)
130
+ # for plugin register.rb files. Useful for development and testing.
131
+ #
132
+ # @param prefix [String] plugin namespace prefix (e.g. 'rosett_ai_engine')
133
+ def discover_custom_path(prefix)
134
+ custom_path = ENV.fetch('RAI_ENGINE_PATH', nil)
135
+ return unless custom_path
136
+
137
+ custom_path.split(':').each do |dir|
138
+ Dir.glob(File.join(dir, 'lib', prefix, '*', 'register.rb')).each do |path|
139
+ lib_dir = File.expand_path('../../..', path)
140
+ $LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir)
141
+ require path
142
+ rescue LoadError => e
143
+ RosettAi.logger.warn("Failed to load custom plugin from #{path}: #{e.message}")
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ module RosettAi
7
+ module Policy
8
+ # Generates compliance audit reports for the current project.
9
+ #
10
+ # Audit results include deny list coverage, protected files,
11
+ # opt-out markers, and tier hierarchy validation.
12
+ class Auditor
13
+ # @param deny_list [DenyList] active deny list
14
+ # @param protected_files [ProtectedFiles] active protected files
15
+ # @param opt_out_scanner [OptOutScanner] scanner instance
16
+ def initialize(deny_list:, protected_files:, opt_out_scanner: OptOutScanner.new)
17
+ @deny_list = deny_list
18
+ @protected_files = protected_files
19
+ @opt_out_scanner = opt_out_scanner
20
+ end
21
+
22
+ # Generates an audit report.
23
+ #
24
+ # @param project_files [Array<String>] list of project files to audit
25
+ # @return [Hash] audit report
26
+ def audit(project_files: [])
27
+ denied = project_files.select { |path| @deny_list.denied?(path) }
28
+ opted_out = @opt_out_scanner.scan(project_files)
29
+
30
+ {
31
+ deny_list_patterns: @deny_list.size,
32
+ denied_files: denied.size,
33
+ protected_files: @protected_files.size,
34
+ opted_out_files: opted_out.size,
35
+ opted_out_paths: opted_out,
36
+ compliant: true
37
+ }
38
+ end
39
+ end
40
+ end
41
+ end