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,475 @@
1
+ ---
2
+ name: gui_plugins
3
+ domain: ui
4
+ version: 0.1.0
5
+ status: implemented
6
+ priority: 3
7
+ author: hugo
8
+ created_at: "2026-03-10"
9
+ modified_at: "2026-03-16"
10
+ modified_by: claude
11
+ depends_on:
12
+ - architecture
13
+ - engine_architecture
14
+ - desktop_integration
15
+ - security
16
+ - distribution
17
+ - error_handling
18
+
19
+ intent: |
20
+ Define the pluggable GUI architecture that treats desktop frontends as
21
+ first-class plugins — the same pattern used for engine plugins. GUI logic
22
+ must not live inside the rosett-ai core gem. Each desktop toolkit (GTK4, Qt6,
23
+ future web) is packaged as a separate gem (rosett-ai-gui-<toolkit>) that
24
+ self-registers via the plugin registry and implements a GuiContract.
25
+
26
+ GUIs are plugin managers. Every GUI must provide full lifecycle management
27
+ for all Rosett-AI plugin types: engines, MCP servers, and content packs. Users
28
+ install, remove, configure, and update plugins through the GUI. Under the
29
+ hood, plugin operations flow through D-Bus to Rosett-AI core, which delegates
30
+ to a PackageManager abstraction (apt, gem, future: dnf, brew, winget).
31
+
32
+ The D-Bus service and client remain in Rosett-AI core. The service enables
33
+ headless automation (CI, scripting, tiling WM integration) without any
34
+ GUI installed. GUI gems are D-Bus clients — they communicate exclusively
35
+ via D-Bus and never import core Ruby modules directly. This ensures that
36
+ any toolkit can be used without coupling to Ruby internals.
37
+
38
+ GUI gems ship all freedesktop.org XDG artifacts: .desktop files, scalable
39
+ icons, AppStream metainfo, and D-Bus activation service files. These are
40
+ installed to standard XDG paths by the package manager (apt) or by the
41
+ gem's post-install hook. All artifacts use the reverse-DNS identifier
42
+ be.neatnerds.rosettai (not be.neatnerds.rosettai — corrected to match the
43
+ actual domain neatnerds.be).
44
+
45
+ GUI gems are version-locked to Rosett-AI core via gemspec dependency:
46
+ spec.add_dependency 'rosett-ai', "= #{VERSION}". This guarantees D-Bus API
47
+ compatibility between the GUI client and the core service.
48
+
49
+ Package manager abstraction provides a uniform interface for installing
50
+ and removing system packages (apt-get), Ruby gems, and future package
51
+ managers (dnf, brew, winget). System package operations require PolicyKit
52
+ (pkexec) for privilege escalation — the GUI never runs as root.
53
+
54
+ Implementation phases:
55
+
56
+ Phase 1 — GuiContract + PackageManager abstraction in core:
57
+ lib/rosett_ai/plugins/gui_contract.rb (contract module)
58
+ lib/rosett_ai/package_manager/ (base, apt, gem backends)
59
+ D-Bus interface extensions for plugin management
60
+ Reverse-DNS rename: be.neatnerds.rosettai → be.neatnerds.rosettai
61
+
62
+ Phase 2 — Extract GTK4 code to rosett-ai-gui-gtk4 gem:
63
+ Move lib/rosett_ai/desktop/gtk4_app.rb → lib/rosett_ai_gui/gtk4/app.rb
64
+ Move lib/rosett_ai/desktop/gtk4_preferences.rb → lib/rosett_ai_gui/gtk4/preferences.rb
65
+ Move lib/rosett_ai/desktop/gui_logger.rb → lib/rosett_ai_gui/gtk4/gui_logger.rb
66
+ Add plugin management views (plugin_manager.rb)
67
+ Self-registration via rosett_ai_gui/gtk4/register.rb
68
+ XDG artifacts in share/ directory
69
+
70
+ Phase 3 — CI, packaging, validation:
71
+ GitLab CI pipeline for Rosett-AI-gui-gtk4 gem
72
+ Debian package build (rosett-ai-gui-gtk4)
73
+ AppStream and desktop-file validation in CI
74
+ Integration tests with mock D-Bus service
75
+
76
+ This design governs pluggable GUI gem architecture, plugin lifecycle
77
+ management, and PackageManager abstraction. The D-Bus service, compositor
78
+ adapters, and desktop service architecture are governed by
79
+ desktop_integration.yml. Engine plugin architecture is governed by
80
+ engine_architecture.yml. Error handling follows error_handling.yml.
81
+
82
+ constraints:
83
+ - "No desktop GUI logic in Rosett-AI core gem — all GUI code lives in rosett-ai-gui-<toolkit> gems"
84
+ - "GUI plugins are separate gems following the pattern rosett-ai-gui-<toolkit>"
85
+ - "GUI gems are version-locked to core via gemspec — spec.add_dependency 'rosett-ai', '= VERSION'"
86
+ - "D-Bus service and D-Bus client library remain in Rosett-AI core"
87
+ - "GUI communicates exclusively via D-Bus — no direct Ruby API imports from core"
88
+ - "All XDG artifacts (.desktop, icons, metainfo, D-Bus service) ship inside the GUI gem or package"
89
+ - "Reverse-DNS identifier is be.neatnerds.rosettai everywhere — bus name, object paths, file names"
90
+ - "Package manager operations for system packages require PolicyKit (pkexec) for privilege escalation"
91
+ - "GUI gems self-register via Gem.find_files('rosett_ai_gui/*/register.rb') — same pattern as engine plugins"
92
+ - "Plugin management in GUI must support all plugin types — engines, MCP servers, content packs"
93
+ - "Security constraints from security.yml apply to all GUI plugin code and D-Bus interactions"
94
+ - "AppStream metainfo and .desktop files must pass their respective validators"
95
+ - "This design governs pluggable GUI gem architecture and plugin lifecycle.
96
+ D-Bus service and compositor adapters are governed by desktop_integration.yml"
97
+
98
+ acceptance_criteria:
99
+ - "GuiContract module exists in lib/rosett_ai/plugins/gui_contract.rb"
100
+ - "GUI gem self-registers via Gem.find_files('rosett_ai_gui/*/register.rb')"
101
+ - "bin/raictl plugins list shows GUI plugins with type :gui alongside engine plugins"
102
+ - ".desktop file installed to share/applications/be.neatnerds.rosettai.desktop passes desktop-file-validate"
103
+ - "Scalable icon installed to share/icons/hicolor/scalable/apps/be.neatnerds.rosettai.svg"
104
+ - "AppStream metainfo at share/metainfo/be.neatnerds.rosettai.metainfo.xml passes appstreamcli validate"
105
+ - "GUI can list installed plugins of all types via D-Bus PluginManager interface"
106
+ - "GUI can install a plugin via D-Bus → PackageManager → apt-get or gem install"
107
+ - "GUI can remove a plugin via D-Bus → PackageManager → apt-get or gem uninstall"
108
+ - "GUI can open a configuration view for any installed plugin"
109
+ - "PackageManager::Apt backend wraps apt-get with pkexec for privilege escalation"
110
+ - "PackageManager::Gem backend wraps gem install/uninstall without privilege escalation"
111
+ - "All occurrences of be.neatnerds.rosettai renamed to be.neatnerds.rosettai in core and specs"
112
+ - "D-Bus service starts on be.neatnerds.rosettai bus name"
113
+ - "rosett-ai-gui-gtk4 gem installs and launches without Rosett-AI core needing any GUI dependencies"
114
+ - "Exit code 0 on success, 1 on plugin operation failure, 5 on missing GUI dependency"
115
+ - "TTY-aware output: formatted table for plugins list when interactive, JSON when piped"
116
+
117
+ examples:
118
+ - scenario: "User installs rosett-ai-gui-gtk4 Debian package"
119
+ expected: |
120
+ Package installs the gem, .desktop file, icon, and metainfo to standard
121
+ XDG paths. GTK4 app appears in GNOME application menu. Launching it
122
+ connects to be.neatnerds.rosettai D-Bus service (auto-activates if needed).
123
+ not: "GUI code is bundled inside Rosett-AI core. .desktop file uses be.neatnerds.rosettai identifier."
124
+ - scenario: "User opens GUI and manages engine plugins"
125
+ expected: |
126
+ Plugin manager view lists installed engines (claude, generic, agents_md).
127
+ User clicks install, selects rosett-ai-engine-ollama from available packages.
128
+ GUI calls D-Bus PluginManager.Install('engine', 'ollama'). Core delegates
129
+ to PackageManager::Apt which runs pkexec apt-get install rosett-ai-engine-ollama.
130
+ After install, new engine appears in the list.
131
+ not: "GUI calls bin/raictl CLI directly. Installation runs without privilege escalation."
132
+ - scenario: "Developer creates a new rosett-ai-gui-web gem"
133
+ expected: |
134
+ Developer implements GuiContract in lib/rosett_ai_gui/web/gui.rb, adds
135
+ register.rb for self-registration. Gem is discoverable by core via
136
+ Gem.find_files. bin/raictl plugins list shows the web GUI alongside gtk4.
137
+ Web GUI communicates with core via D-Bus WebSocket bridge.
138
+ not: "Web GUI requires changes to Rosett-AI core. Developer must modify plugin registry manually."
139
+ - scenario: "User on Fedora installs rosett-ai-gui-gtk4 RPM"
140
+ expected: |
141
+ PackageManager::Dnf backend (future) handles installation. Same D-Bus
142
+ communication, same plugin management UI. Only the package manager
143
+ backend differs. Falls back to PackageManager::Gem if no system
144
+ package manager is configured.
145
+ not: "Installation fails because apt is hardcoded. GUI assumes Debian-based system."
146
+
147
+ anti_patterns:
148
+ - "GUI code in Rosett-AI core gem (all GUI logic belongs in rosett-ai-gui-<toolkit> gems)"
149
+ - "GUI importing core Ruby modules directly (must communicate via D-Bus only)"
150
+ - "Hardcoding apt as the only package manager (use PackageManager abstraction)"
151
+ - "Using be.neatnerds.rosettai instead of be.neatnerds.rosettai (domain is neatnerds.be)"
152
+ - "Plugin management bypassing D-Bus (no direct CLI calls from GUI process)"
153
+ - "GUI running package operations as root (must use pkexec for privilege escalation)"
154
+ - "Tight coupling between GUI gem and a specific package manager backend"
155
+ - "Shipping XDG artifacts from Rosett-AI core instead of from the GUI gem"
156
+ - "Version mismatch between GUI gem and core (must be exact version lock)"
157
+
158
+ gui_notes: |
159
+ Document interactions (cross-references):
160
+
161
+ 1. desktop_integration.yml: gui_plugins governs pluggable GUI gem
162
+ architecture and plugin lifecycle. desktop_integration governs D-Bus
163
+ service, compositor adapters, and desktop service architecture.
164
+
165
+ 2. engine_architecture.yml: engine plugins and GUI plugins share the
166
+ same self-registration pattern (Gem.find_files). GUI plugin management
167
+ covers engine install/remove/configure via D-Bus.
168
+
169
+ 3. distribution.yml: GUI gems are distributed as Debian packages
170
+ alongside Rosett-AI core. Same Pulp repository, same CI pipeline pattern.
171
+
172
+ 4. security.yml: GUI D-Bus interactions follow security constraints.
173
+ PackageManager uses array-form system() for subprocess spawning.
174
+
175
+ 5. error_handling.yml: plugin operation errors follow the structured
176
+ error hierarchy. Exit codes for plugins list/install/remove commands.
177
+
178
+ 6. content_packs.yml: GUI plugin management covers content pack
179
+ install/remove alongside engines and MCP servers.
180
+
181
+ GuiContract Definition:
182
+
183
+ module RosettAi::Plugins::GuiContract
184
+ include RosettAi::Plugins::Contract
185
+
186
+ def plugin_type = :gui
187
+
188
+ # Identity
189
+ def gui_name # 'gtk4', 'qt6', 'web'
190
+ def application_id # 'be.neatnerds.rosettai'
191
+ def toolkit # 'gtk4', 'qt6', 'web'
192
+
193
+ # Lifecycle
194
+ def available? # true if system dependencies are met
195
+ def launch(argv) # Start the GUI application
196
+ def required_system_packages # ['libgtk-4-1', 'libadwaita-1-0']
197
+ def manifest_path # Path to conf/manifest.yml in the gem
198
+
199
+ # Plugin management (required — all GUIs must support this)
200
+ def plugin_list_view # Show installed plugins of all types
201
+ def plugin_install_dialog(type) # Install dialog for :engine / :mcp / :content
202
+ def plugin_remove_dialog(type, name) # Removal confirmation for a plugin
203
+ def plugin_configure_view(type, name) # Configuration view for a plugin
204
+ end
205
+
206
+ Package Manager Abstraction:
207
+
208
+ module RosettAi::PackageManager
209
+ class Base
210
+ def install(package_name) # Install a package
211
+ def remove(package_name) # Remove a package
212
+ def installed?(package_name) # Check if a package is installed
213
+ def available_packages(pattern) # Search available packages
214
+ def update_index # Refresh package list / cache
215
+ end
216
+
217
+ class Apt < Base
218
+ # Wraps apt-get via pkexec for privilege escalation
219
+ # Uses array-form system() — never string interpolation
220
+ # Parses dpkg-query for installed? checks
221
+ end
222
+
223
+ class Gem < Base
224
+ # Wraps Gem::Installer / Gem::Uninstaller
225
+ # No privilege escalation needed (user gem path)
226
+ # Fallback when no system package manager is available
227
+ end
228
+
229
+ # Future backends:
230
+ # class Dnf < Base — Fedora/RHEL (dnf install)
231
+ # class Brew < Base — macOS (brew install)
232
+ # class Winget < Base — Windows (winget install)
233
+ end
234
+
235
+ D-Bus PluginManager Interface (new, added to core service):
236
+
237
+ be.neatnerds.rosettai.PluginManager:
238
+ Methods:
239
+ ListPlugins(s type) -> a(sssa{sv})
240
+ # type: 'engine', 'gui', 'mcp', 'content'
241
+ # Returns array of (name, version, status, metadata)
242
+ InstallPlugin(s type, s name) -> (bs)
243
+ # Returns (success, message)
244
+ RemovePlugin(s type, s name) -> (bs)
245
+ # Returns (success, message)
246
+ GetPluginConfig(s type, s name) -> a{sv}
247
+ # Returns plugin configuration as dict
248
+ SetPluginConfig(s type, s name, a{sv} config) -> (bs)
249
+ # Updates plugin configuration
250
+ Signals:
251
+ PluginInstalled(s type, s name, s version)
252
+ PluginRemoved(s type, s name)
253
+ PluginConfigChanged(s type, s name)
254
+
255
+ GUI Gem Directory Structure:
256
+
257
+ rosett-ai-gui-gtk4/
258
+ ├── lib/rosett_ai_gui/gtk4/
259
+ │ ├── register.rb # Self-registration with plugin registry
260
+ │ ├── gui.rb # GuiContract implementation
261
+ │ ├── app.rb # Gtk4App (extracted from core desktop/)
262
+ │ ├── preferences.rb # Gtk4Preferences (extracted from core)
263
+ │ ├── gui_logger.rb # GuiLogger (extracted from core)
264
+ │ ├── plugin_manager.rb # Plugin management views (new)
265
+ │ └── version.rb # Version constant (locked to core)
266
+ ├── conf/manifest.yml # GUI capability manifest
267
+ ├── share/
268
+ │ ├── applications/
269
+ │ │ └── be.neatnerds.rosettai.desktop
270
+ │ ├── icons/hicolor/scalable/apps/
271
+ │ │ └── be.neatnerds.rosettai.svg
272
+ │ ├── metainfo/
273
+ │ │ └── be.neatnerds.rosettai.metainfo.xml
274
+ │ └── dbus-1/services/
275
+ │ └── be.neatnerds.rosettai.Gui.service
276
+ ├── packaging/scripts/
277
+ │ ├── postinst # Install XDG artifacts, update caches
278
+ │ ├── prerm # Pre-removal cleanup
279
+ │ └── postrm # Post-removal cache updates
280
+ ├── spec/
281
+ │ ├── rosett_ai_gui/gtk4/
282
+ │ │ ├── gui_spec.rb
283
+ │ │ ├── app_spec.rb
284
+ │ │ ├── plugin_manager_spec.rb
285
+ │ │ └── register_spec.rb
286
+ │ └── support/
287
+ │ └── dbus_mock.rb # Mock D-Bus service for tests
288
+ ├── rosett-ai-gui-gtk4.gemspec
289
+ ├── Gemfile
290
+ ├── .rubocop.yml
291
+ └── .reek.yml
292
+
293
+ GUI Manifest (conf/manifest.yml in rosett-ai-gui-gtk4):
294
+
295
+ name: gtk4
296
+ display_name: GTK4 Desktop App
297
+ plugin_type: gui
298
+ toolkit: gtk4
299
+ application_id: be.neatnerds.rosettai
300
+ required_system_packages:
301
+ - libgtk-4-1
302
+ - libadwaita-1-0
303
+ - gir1.2-gtk-4.0
304
+ - gir1.2-adw-1
305
+ capabilities:
306
+ plugin_management: true
307
+ preferences_dialog: true
308
+ system_tray: false # SNI is in core D-Bus service
309
+ focus_monitoring: false # Focus monitor is in core D-Bus service
310
+ xdg_artifacts:
311
+ desktop_file: share/applications/be.neatnerds.rosettai.desktop
312
+ icon_scalable: share/icons/hicolor/scalable/apps/be.neatnerds.rosettai.svg
313
+ metainfo: share/metainfo/be.neatnerds.rosettai.metainfo.xml
314
+
315
+ Reverse-DNS Rename Scope (be.neatnerds.rosettai → be.neatnerds.rosettai):
316
+
317
+ Core source files:
318
+ lib/rosett_ai/dbus/service.rb — BUS_NAME constant
319
+ lib/rosett_ai/dbus/manager_interface.rb — interface name string
320
+ lib/rosett_ai/dbus/focus_monitor_interface.rb — interface name string
321
+ lib/rosett_ai/dbus/status_notifier_interface.rb — interface name string
322
+ lib/rosett_ai/desktop/gtk4_app.rb — APPLICATION_ID constant
323
+ lib/rosett_ai/desktop/dbus_client.rb — bus name, object path
324
+ lib/rosett_ai/thor/tasks/dbus.rb — bus name references
325
+
326
+ XDG artifact files (rename file + update contents):
327
+ share/applications/be.neatnerds.rosettai.desktop
328
+ → share/applications/be.neatnerds.rosettai.desktop
329
+ share/dbus-1/services/be.neatnerds.rosettai.service
330
+ → share/dbus-1/services/be.neatnerds.rosettai.service
331
+ share/dbus-1/interfaces/be.neatnerds.rosettai.xml
332
+ → share/dbus-1/interfaces/be.neatnerds.rosettai.xml
333
+
334
+ Spec files:
335
+ spec/rosett_ai/dbus/service_spec.rb
336
+ spec/rosett_ai/dbus/manager_interface_spec.rb
337
+ spec/rosett_ai/dbus/focus_monitor_interface_spec.rb
338
+ spec/rosett_ai/dbus/status_notifier_interface_spec.rb
339
+ spec/rosett_ai/desktop/dbus_client_spec.rb
340
+ spec/rosett_ai/desktop/gtk4_app_spec.rb
341
+ spec/rosett_ai/thor/tasks/dbus_spec.rb
342
+
343
+ Documentation:
344
+ CLAUDE.md, README.md, CHANGELOG.md, DESKTOP.md
345
+ doc/man/rai.1.ronn
346
+ doc/IMPLEMENTATION_PLAN.md, doc/ARCHITECTURE.md
347
+ conf/design/desktop_integration.yml
348
+
349
+ Self-Registration (lib/rosett_ai_gui/gtk4/register.rb):
350
+
351
+ module RosettAiGui
352
+ module Gtk4
353
+ class Register
354
+ def self.call(registry)
355
+ registry.register(
356
+ name: 'gtk4',
357
+ type: :gui,
358
+ klass: -> { require 'rosett_ai_gui/gtk4/gui'; RosettAiGui::Gtk4::Gui },
359
+ manifest: File.expand_path('../../conf/manifest.yml', __dir__)
360
+ )
361
+ end
362
+ end
363
+ end
364
+ end
365
+
366
+ Gemspec Pattern (rosett-ai-gui-gtk4.gemspec):
367
+
368
+ Gem::Specification.new do |spec|
369
+ spec.name = 'rosett-ai-gui-gtk4'
370
+ spec.version = RosettAiGui::Gtk4::VERSION
371
+ spec.summary = 'GTK4 desktop interface for Rosett-AI'
372
+ spec.license = 'GPL-3.0-only'
373
+ spec.authors = ['Hugo Antonio Sepulveda Manriquez']
374
+ spec.email = ['hugo@neatnerds.be']
375
+
376
+ spec.add_dependency 'rosett-ai', "= #{RosettAiGui::Gtk4::VERSION}"
377
+ spec.add_dependency 'gtk4', '~> 4.2'
378
+ spec.add_dependency 'adwaita', '~> 0.5'
379
+
380
+ spec.metadata['rubygems_mfa_required'] = 'true'
381
+ end
382
+
383
+ interactions:
384
+ - action: "List installed plugins"
385
+ tui: "bin/raictl plugins list"
386
+ gtk4: "Plugin Manager view in main window"
387
+ qt6: "KCM plugin management panel"
388
+ - action: "Install a new engine"
389
+ tui: "bin/raictl plugins install engine ollama"
390
+ gtk4: "Plugin Manager → Install → select engine from list"
391
+ qt6: "KCM plugin panel → Install button → engine list"
392
+ - action: "Remove a plugin"
393
+ tui: "bin/raictl plugins remove engine ollama"
394
+ gtk4: "Plugin Manager → select plugin → Remove button → confirmation dialog"
395
+ qt6: "KCM plugin panel → select plugin → Remove → confirmation"
396
+ - action: "Configure a plugin"
397
+ tui: "bin/raictl plugins configure engine claude"
398
+ gtk4: "Plugin Manager → select plugin → Configure button → settings view"
399
+ qt6: "KCM plugin panel → select plugin → Configure → settings form"
400
+ - action: "Launch GUI application"
401
+ tui: "bin/raictl gui launch gtk4"
402
+ gtk4: "Desktop menu entry or bin/rai-gtk4"
403
+ qt6: "System Settings → rosett-ai module or bin/rai-qt6"
404
+
405
+ accessibility:
406
+ roles:
407
+ - element: "plugin_list"
408
+ role: "listbox"
409
+ label: "Installed plugins"
410
+ description: "List of all installed rai plugins grouped by type"
411
+ - element: "plugin_install_button"
412
+ role: "button"
413
+ label: "Install plugin"
414
+ description: "Opens the plugin installation dialog"
415
+ - element: "plugin_remove_button"
416
+ role: "button"
417
+ label: "Remove plugin"
418
+ description: "Removes the selected plugin after confirmation"
419
+ - element: "plugin_configure_button"
420
+ role: "button"
421
+ label: "Configure plugin"
422
+ description: "Opens configuration view for the selected plugin"
423
+ - element: "package_manager_status"
424
+ role: "status"
425
+ label: "Package manager status"
426
+ description: "Shows which package manager backend is active and its state"
427
+ keyboard:
428
+ - key: "Tab"
429
+ action: "Navigate between plugin list and action buttons"
430
+ - key: "Arrow keys"
431
+ action: "Navigate plugin list items"
432
+ - key: "Enter"
433
+ action: "Activate selected button or open plugin details"
434
+ - key: "Delete"
435
+ action: "Remove selected plugin (with confirmation)"
436
+ - key: "Escape"
437
+ action: "Close dialog or cancel operation"
438
+ announcements:
439
+ - event: "plugin_installed"
440
+ announce: "Plugin <name> installed successfully"
441
+ priority: "polite"
442
+ - event: "plugin_removed"
443
+ announce: "Plugin <name> removed"
444
+ priority: "polite"
445
+ - event: "plugin_install_failed"
446
+ announce: "Failed to install plugin <name>: <error>"
447
+ priority: "assertive"
448
+ - event: "privilege_escalation"
449
+ announce: "Authentication required to install system package"
450
+ priority: "assertive"
451
+ target_sizes:
452
+ minimum: "24x24dp"
453
+ recommended: "44x44dp"
454
+ timing:
455
+ no_time_limits: true
456
+ animations_respect_prefers_reduced_motion: true
457
+
458
+ preferences:
459
+ language: ruby
460
+ patterns:
461
+ - "GUI as plugin (self-registering gem, GuiContract)"
462
+ - "PackageManager abstraction (Apt, Gem, future: Dnf, Brew)"
463
+ - "D-Bus exclusive IPC (no direct Ruby API imports)"
464
+ - "Reverse-DNS naming (be.neatnerds.rosettai)"
465
+ - "XDG compliance for desktop artifacts"
466
+ - "Version-locked gems (exact dependency on core)"
467
+ - "Privilege escalation via PolicyKit (pkexec)"
468
+ testing: rspec with mock D-Bus service, GuiContract compliance tests,
469
+ PackageManager backend scenarios, plugin install/remove lifecycle,
470
+ XDG artifact validation, version lock enforcement, and privilege
471
+ escalation handling
472
+ gems:
473
+ - ruby-dbus (core, for D-Bus client)
474
+ - gtk4 (rosett-ai-gui-gtk4 only)
475
+ - adwaita (rosett-ai-gui-gtk4 only)
@@ -0,0 +1,84 @@
1
+ ---
2
+ name: i18n
3
+ domain: i18n
4
+ version: 1.1.0
5
+ status: implemented
6
+ priority: 3
7
+ author: hugo
8
+ created_at: "2026-02-18"
9
+ modified_at: "2026-03-17"
10
+ modified_by: claude
11
+ depends_on:
12
+ - architecture
13
+ - compiler
14
+
15
+ intent: |
16
+ Enable rosett-ai to support any language in the world across all surfaces: UI
17
+ strings (TUI + GUI), CLI output, documentation, and validation messages.
18
+ The approach uses ruby-i18n YAML as the single source of truth, compiled
19
+ to platform-native formats for each GUI toolkit (gettext for GTK4/KDE,
20
+ Qt Linguist for Qt6). This follows the 'author once, compile down'
21
+ principle already established for behaviour and design compilation.
22
+
23
+ constraints:
24
+ - All user-facing strings must be externalized to locale files (never hardcoded)
25
+ - ruby-i18n YAML format is the single source of truth for all translations
26
+ - Locale files must be compiled to platform-native formats (gettext .po/.mo, Qt .ts/.qm)
27
+ - CLDR plural rules must be used for correct pluralization in all languages
28
+ - RTL languages (Arabic, Hebrew, Persian, Urdu) must be fully supported
29
+ - All files must be UTF-8 encoded — no exceptions, no legacy encoding support
30
+ - English (en) is always the fallback locale
31
+ - Missing translations must fall back gracefully and never crash the application
32
+ - Locale resolution order is explicit flag > config file > LANG env > English fallback
33
+ - All I/O assumes UTF-8 (enforced at startup with a terminal capability check)
34
+
35
+ acceptance_criteria:
36
+ - locales/en.yml exists with complete English translations for all UI strings
37
+ - bin/raictl compile --locales produces gettext and Qt Linguist files
38
+ - bin/raictl --locale fr displays French strings (with English fallback for missing keys)
39
+ - Pluralization works correctly for Arabic (6 forms) and Polish (4 forms)
40
+ - RTL text direction is correctly applied when locale is ar, he, fa, or ur
41
+ - Terminal UTF-8 capability is checked at startup with clear error if unsupported
42
+ - bin/raictl documentation translate --from en --to fr produces draft translation
43
+ - Fallback chain works correctly (nl_BE > nl > en)
44
+
45
+ examples:
46
+ - scenario: "User runs bin/raictl compile on a French system (LANG=fr_FR.UTF-8)"
47
+ expected: |
48
+ CLI output is in French. 'Compiled 3 rules successfully' becomes
49
+ '3 règles compilées avec succès'. Validation errors are in French.
50
+ not: "Output is in English despite French locale. Mixed English/French output."
51
+ - scenario: "Arabic translation has 6 plural forms for 'rules compiled'"
52
+ expected: |
53
+ 0 rules: zero form. 1 rule: one form. 2 rules: two form.
54
+ 3-10 rules: few form. 11-99 rules: many form. 100+ rules: other form.
55
+ not: "Only singular/plural distinction. Wrong form used for Arabic numbers."
56
+ - scenario: "Developer adds a new CLI command but forgets to add locale strings"
57
+ expected: |
58
+ English key is used as fallback. Log warning about missing translation
59
+ key in development mode. rubocop-i18n (if available) flags hardcoded strings.
60
+ not: "Application crashes with MissingTranslationData error."
61
+ - scenario: "User wants to help translate rosett-ai to their language"
62
+ expected: |
63
+ Copy locales/en.yml to locales/xx.yml. Translate strings. Submit PR.
64
+ bin/raictl compile --locales generates platform-native files from new locale.
65
+ not: "Translator must understand gettext .po format or Qt Linguist .ts format."
66
+
67
+ anti_patterns:
68
+ - Hardcoded user-facing strings in source code
69
+ - Using gettext or Qt Linguist as source format (these are compilation targets)
70
+ - Assuming English plural rules (singular/plural only) for all languages
71
+ - Ignoring RTL text direction for Arabic, Hebrew, Persian, Urdu
72
+ - Legacy encoding support (Shift_JIS, ISO-8859-1, etc.)
73
+ - Crashing on missing translation keys instead of falling back
74
+ - Locale detection that ignores system LANG environment variable
75
+
76
+ preferences:
77
+ language: ruby
78
+ gems:
79
+ - i18n
80
+ - gettext
81
+ patterns:
82
+ - single_source_of_truth_locale_files
83
+ - compile_to_platform_native
84
+ - graceful_fallback_chain
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: integration_testing
3
+ domain: core
4
+ version: "1.1.0"
5
+ status: implemented
6
+ intent: |
7
+ Define a comprehensive integration testing strategy for rosett-ai that ensures
8
+ .deb packages are built from source and verified against InSpec controls
9
+ inside isolated Vagrant/libvirt VMs. The strategy supports both local developer
10
+ workstations and GitLab CI, and is gated so that no CLI change can land on
11
+ main without passing integration verification.
12
+
13
+ This design addresses a systemic gap discovered on 2026-04-07/08: all 37
14
+ InSpec controls were authored speculatively between 2026-03-09 and
15
+ 2026-03-23, never executed against a real VM, and accumulated 26 breaking
16
+ CLI changes over 30 days before the first real run. Three controls were
17
+ wrong at the moment they were written.
18
+
19
+ constraints:
20
+ - "Must use Vagrant with libvirt provider (KVM/QEMU) for isolation"
21
+ - "Must install pre-built .deb from pkg/ directory (data_path in kitchen.yml)"
22
+ - "Must install and test ALL engine .debs when present"
23
+ - "Must run as a GitLab CI stage, blocking merge to main on failure"
24
+ - "Must be runnable locally via a single command"
25
+ - "Provisioner must handle locale, ownership, and build deps automatically"
26
+ - "CI job must complete in under 20 minutes"
27
+ - "Must detect when CLI changes break InSpec controls before merge"
28
+ - "kitchen-vagrant pinned to 1.14.2 (last MPL-2.0 compatible with Vagrant 2.3.x)"
29
+
30
+ acceptance_criteria:
31
+ - "`rake build:package && BUNDLE_GEMFILE=Gemfile.integration bundle exec kitchen test` passes all controls"
32
+ - "GitLab CI includes an integration stage with kitchen verify"
33
+ - "kitchen.yml uses vagrant driver with libvirt provider"
34
+ - "README or INSTALL.md documents how to run integration tests locally"
35
+
36
+ examples:
37
+ - scenario: "Developer modifies Thor subcommand structure"
38
+ expected: "CI warns about stale InSpec controls referencing old command names"
39
+ - scenario: "CI runs on merge request to main"
40
+ expected: "Integration stage installs .deb in clean VM, runs kitchen verify, blocks merge on failure"
41
+ - scenario: "Developer runs integration tests locally"
42
+ expected: "`BUNDLE_GEMFILE=Gemfile.integration bundle exec kitchen test` completes via Vagrant/libvirt"
43
+
44
+ preferences:
45
+ language: ruby
46
+ patterns:
47
+ - "kitchen.yml uses vagrant driver with libvirt provider"
48
+ - "Two suites: rai-context (path resolution) and rai-commands (CLI commands)"
49
+ - "provision.sh is the single source of truth for VM setup"
50
+ - "data_path: pkg syncs pre-built .deb packages to guest"
51
+ testing: "InSpec 4.x via kitchen-inspec"
52
+
53
+ anti_patterns:
54
+ - "Do not write InSpec controls without running them against a real target"
55
+ - "Do not modify CLI subcommand structure without grepping test/integration/"
56
+ - "Do not use sudo in InSpec verifier (breaks shell builtins)"