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,289 @@
1
+ ---
2
+ name: desktop_integration
3
+ domain: ui
4
+ version: 0.1.0
5
+ status: implemented
6
+ priority: 3
7
+ author: hugo
8
+ created_at: "2026-02-24"
9
+ modified_at: "2026-03-16"
10
+ modified_by: claude
11
+ depends_on:
12
+ - architecture
13
+ - ui_framework
14
+ - accessibility
15
+ - i18n
16
+ - security
17
+ - error_handling
18
+
19
+ intent: |
20
+ Define how rosett-ai integrates with Linux desktop environments via a D-Bus
21
+ session bus service (be.neatnerds.rosettai) and optional desktop-specific
22
+ frontends. The D-Bus service is the central IPC layer — all desktop
23
+ variants (GTK4 standalone app, KDE KCM plugin, CLI tools, tiling WM
24
+ scripts) consume the same D-Bus API. Includes system tray presence via
25
+ StatusNotifierItem and global hotkey registration via XDG GlobalShortcuts
26
+ portal.
27
+
28
+ The D-Bus service is implemented in Ruby using the ruby-dbus gem. It
29
+ exposes interfaces for configuration management, focus monitoring, and
30
+ automatic context switching. The service auto-activates via a standard
31
+ D-Bus .service file — no manual startup required. Rosett-AI core remains
32
+ fully functional without D-Bus (CLI/TUI degraded mode).
33
+
34
+ Focus monitoring uses compositor-specific adapters (GNOME D-Bus
35
+ extension, KWin D-Bus scripting, i3ipc gem, Hyprland socket2) that
36
+ feed into a unified FocusChanged D-Bus signal. This enables automatic
37
+ context switching when the user changes application focus.
38
+
39
+ Phased implementation:
40
+
41
+ Phase 1 — D-Bus Service Foundation:
42
+ be.neatnerds.rosettai D-Bus service (ruby-dbus)
43
+ StatusNotifierItem for system tray
44
+ FocusMonitor with compositor adapters
45
+ GlobalShortcuts portal registration
46
+ CLI command: bin/raictl --dbus-service
47
+
48
+ Phase 2 — GTK4 Desktop App (rosett-ai-gtk4):
49
+ Standalone libadwaita app consuming D-Bus service
50
+ AdwPreferencesDialog for settings
51
+ GNOME HIG compliance
52
+ Dogtail integration tests
53
+ .desktop file with DBusActivatable=true
54
+
55
+ Phase 3 — KDE KCM Module (rosett-ai-kde):
56
+ C++/QML thin shim consuming D-Bus service via QtDBus
57
+ KCMUtils.SimpleKCM + Kirigami.FormLayout
58
+ KDE HIG compliance
59
+ Spix / Dogtail integration tests
60
+
61
+ This design governs D-Bus IPC, compositor adapters, and desktop service
62
+ architecture. Pluggable GUI gem packaging and plugin lifecycle management
63
+ is governed by gui_plugins.yml. Accessibility requirements are governed
64
+ by accessibility.yml. Error handling follows error_handling.yml.
65
+
66
+ constraints:
67
+ - "D-Bus session bus is the sole IPC mechanism between rosett-ai backend and desktop frontends"
68
+ - "The D-Bus service is implemented in Ruby using ruby-dbus gem — no C/C++ daemon"
69
+ - "D-Bus service auto-activates via .service file — no manual startup required"
70
+ - "Rosett-AI core package must remain functional without D-Bus (CLI/TUI degraded mode)"
71
+ - "GNOME frontend is a standalone libadwaita app (no gnome-control-center plugin — impossible)"
72
+ - "KDE frontend is a KCM plugin (C++/QML thin shim) consuming the D-Bus service"
73
+ - "StatusNotifierItem is implemented in the D-Bus service itself — no GUI dependency for tray"
74
+ - "Global hotkeys use org.freedesktop.portal.GlobalShortcuts where available;
75
+ compositor-specific config as documented fallback"
76
+ - "All D-Bus interfaces provide introspection XML"
77
+ - "Security constraints from security.yml apply to all D-Bus method handlers"
78
+ - "Follow reverse-DNS naming — bus name be.neatnerds.rosettai, object path /be/neatnerds/rosett-ai"
79
+ - "This design governs D-Bus IPC, compositor adapters, and desktop service
80
+ architecture. Pluggable GUI gem packaging is governed by gui_plugins.yml"
81
+
82
+ acceptance_criteria:
83
+ - "be.neatnerds.rosettai service starts on D-Bus session bus via bin/raictl --dbus-service"
84
+ - "Service auto-activates when any client calls a method (via .service file)"
85
+ - "busctl --user introspect be.neatnerds.rosettai /be/neatnerds/rosett-ai shows all interfaces"
86
+ - "GTK4 app communicates exclusively via D-Bus (no direct Ruby API calls)"
87
+ - "KDE KCM communicates exclusively via D-Bus (via QtDBus)"
88
+ - "CLI command bin/raictl dbus status shows service state"
89
+ - "StatusNotifierItem appears in KDE Plasma system tray and Waybar without GTK4 app running"
90
+ - "bin/raictl --dbus-service gracefully degrades if D-Bus session bus unavailable"
91
+ - "Focus monitor detects compositor type and subscribes to focus events"
92
+ - "FocusChanged signal emitted on D-Bus when active window changes"
93
+ - "Global hotkey registration succeeds on KDE Plasma via GlobalShortcuts portal"
94
+ - "Exit code 0 on success, 1 on D-Bus connection failure, 5 on missing ruby-dbus dependency"
95
+ - "TTY-aware output: formatted status when interactive, JSON when piped"
96
+
97
+ examples:
98
+ - scenario: "D-Bus service on sway — user runs sway, installs Rosett-AI core only"
99
+ expected: |
100
+ bin/raictl compile works via CLI. D-Bus service auto-activates when
101
+ Waybar's SNI module queries the tray. Tray icon appears. Focus monitor
102
+ uses i3ipc adapter for sway IPC socket.
103
+ not: "Service crashes because no GNOME/KDE present. Tray requires GTK4 app."
104
+ - scenario: "GTK4 app on GNOME — user installs rosett-ai + rosett-ai-gtk4"
105
+ expected: |
106
+ Launches via desktop file. App connects to be.neatnerds.rosettai via
107
+ GDBus. All operations go through D-Bus. Settings use
108
+ AdwPreferencesDialog with instant-apply pattern.
109
+ not: "GTK4 app imports Ruby Rosett-AI modules directly. Uses OK/Apply buttons."
110
+ - scenario: "Focus-based context switching — user has VS Code and Firefox open"
111
+ expected: |
112
+ User switches to Firefox. Focus monitor detects app_id change, emits
113
+ FocusChanged('firefox', ...). Manager loads browser memory profile.
114
+ ContextChanged signal emitted on D-Bus.
115
+ not: "Polling loop checks focus every N seconds. Context switch requires manual action."
116
+ - scenario: "Hotkey triggers compile — user presses configured hotkey"
117
+ expected: |
118
+ GlobalShortcuts portal delivers event to D-Bus service. Service runs
119
+ compile. Notification sent via org.freedesktop.Notifications.
120
+ not: "rosett-ai grabs keyboard input directly. Hotkey only works under specific compositor."
121
+
122
+ anti_patterns:
123
+ - "QProcess/subprocess calls from GUI to Rosett-AI CLI (bypasses D-Bus)"
124
+ - "Polling for focus changes instead of event-driven subscription"
125
+ - "Implementing SNI in the GTK4 app instead of the D-Bus service"
126
+ - "Assuming GlobalShortcuts portal is available on all compositors"
127
+ - "Business logic in KCM C++/QML layer or GTK4 UI layer"
128
+ - "Hardcoded compositor detection instead of environment variable + D-Bus name probing"
129
+
130
+ gui_notes: |
131
+ Document interactions (cross-references):
132
+
133
+ 1. gui_plugins.yml: desktop_integration provides D-Bus service and
134
+ compositor adapters. gui_plugins governs pluggable GUI gem packaging,
135
+ plugin lifecycle management, and PackageManager abstraction.
136
+
137
+ 2. accessibility.yml: desktop integration implements EN 301 549
138
+ requirements for D-Bus service responses, SNI tray, and focus
139
+ announcements.
140
+
141
+ 3. security.yml: all D-Bus method handlers follow security constraints.
142
+ No secret exposure via D-Bus properties or signals.
143
+
144
+ 4. error_handling.yml: D-Bus method errors map to structured error
145
+ hierarchy. Exit codes for dbus status command.
146
+
147
+ 5. ui_framework.yml: TUI is the primary interface. Desktop integration
148
+ adds D-Bus IPC layer for optional GUI frontends.
149
+
150
+ 6. i18n.yml: D-Bus service status messages and error responses are
151
+ localised via gettext.
152
+
153
+ D-Bus Interfaces:
154
+
155
+ be.neatnerds.rosettai.Manager:
156
+ Methods:
157
+ Compile() -> s # Run compilation, return status
158
+ SwitchContext(s context_name) # Switch AI context by name
159
+ GetStatus() -> a{sv} # Return service status as dict
160
+ Properties:
161
+ Version: s (read) # Service version string
162
+ Signals:
163
+ ContextChanged(s context_name) # Emitted after context switch
164
+
165
+ be.neatnerds.rosettai.FocusMonitor:
166
+ Methods:
167
+ GetCurrentFocus() -> (ss) # Return (app_id, window_title)
168
+ Signals:
169
+ FocusChanged(s app_id, s title) # Emitted on active window change
170
+
171
+ org.kde.StatusNotifierItem:
172
+ Standard SNI interface for system tray icon. Implemented in the D-Bus
173
+ service itself — no GTK4 or Qt6 dependency. Consumed by KDE Plasma
174
+ system tray, Waybar, swaybar, and other SNI-capable panels.
175
+
176
+ org.freedesktop.portal.GlobalShortcuts:
177
+ Consumer (not provider). The D-Bus service registers hotkey bindings
178
+ via the XDG GlobalShortcuts portal. Specific key bindings are
179
+ user-configurable — not hardcoded. Fallback: compositor-specific
180
+ config documentation (sway bindsym, Hyprland bind, etc.).
181
+
182
+ D-Bus Service File (/usr/share/dbus-1/services/be.neatnerds.rosettai.service):
183
+ [D-BUS Service]
184
+ Name=be.neatnerds.rosettai
185
+ Exec=/usr/bin/raictl --dbus-service
186
+
187
+ Compositor Detection (auto):
188
+ 1. HYPRLAND_INSTANCE_SIGNATURE → :hyprland
189
+ 2. SWAYSOCK → :sway
190
+ 3. I3SOCK → :i3
191
+ 4. D-Bus name org.gnome.Shell active → :gnome
192
+ 5. D-Bus name org.kde.KWin active → :kwin
193
+ 6. DISPLAY set, WAYLAND_DISPLAY unset → :x11
194
+ 7. else → :unknown
195
+
196
+ Focus Adapter Mapping:
197
+ :gnome → GNOME Shell extension D-Bus interface
198
+ :kwin → KWin D-Bus scripting API (org.kde.KWin)
199
+ :sway → i3ipc gem (window::focus event)
200
+ :i3 → i3ipc gem (window::focus event)
201
+ :hyprland → Hyprland IPC socket2 (activewindow>> event)
202
+ :x11 → _NET_ACTIVE_WINDOW property change (xprop)
203
+ :unknown → no focus monitoring (degraded mode)
204
+
205
+ interactions:
206
+ - action: "View rosett-ai status"
207
+ tui: "bin/raictl status"
208
+ gtk4: "Preferences dialog status page"
209
+ qt6: "KCM panel status section"
210
+ - action: "Switch AI context"
211
+ tui: "bin/raictl context switch <name>"
212
+ gtk4: "Tray menu context submenu"
213
+ qt6: "KCM dropdown or tray menu"
214
+ - action: "Trigger compile"
215
+ tui: "bin/raictl compile"
216
+ gtk4: "Hotkey or tray action"
217
+ qt6: "KCM button or hotkey"
218
+ - action: "View D-Bus service state"
219
+ tui: "bin/raictl dbus status"
220
+ gtk4: "Status indicator in preferences"
221
+ qt6: "KCM status widget"
222
+
223
+ accessibility:
224
+ roles:
225
+ - element: "tray_menu"
226
+ role: "menu"
227
+ label: "Rosett-AI tray menu"
228
+ description: "System tray context menu for quick actions"
229
+ - element: "preferences_dialog"
230
+ role: "dialog"
231
+ label: "Rosett-AI preferences"
232
+ description: "Configuration dialog (GTK4: AdwPreferencesDialog)"
233
+ - element: "focus_indicator"
234
+ role: "status"
235
+ label: "Current focus application"
236
+ description: "Shows which application currently has focus"
237
+ - element: "context_selector"
238
+ role: "listbox"
239
+ label: "AI context selector"
240
+ description: "Dropdown or list for switching AI context"
241
+ keyboard:
242
+ - key: "Menu key or right-click"
243
+ action: "Open tray context menu"
244
+ - key: "Arrow keys"
245
+ action: "Navigate tray menu items"
246
+ - key: "Enter"
247
+ action: "Activate selected tray menu item"
248
+ - key: "Escape"
249
+ action: "Close tray menu or preferences dialog"
250
+ announcements:
251
+ - event: "context_switch"
252
+ announce: "Context switched to <name>"
253
+ priority: "polite"
254
+ - event: "compile_complete"
255
+ announce: "Compilation completed successfully"
256
+ priority: "polite"
257
+ - event: "compile_error"
258
+ announce: "Compilation failed: <error>"
259
+ priority: "assertive"
260
+ - event: "service_unavailable"
261
+ announce: "D-Bus service unavailable — running in degraded mode"
262
+ priority: "assertive"
263
+ - event: "focus_change"
264
+ announce: "Focus changed to <app_id>"
265
+ priority: "polite"
266
+
267
+ preferences:
268
+ language: ruby
269
+ patterns:
270
+ - "Adapter pattern for compositor-specific focus monitors"
271
+ - "Event-driven subscription (not polling)"
272
+ - "Graceful degradation when D-Bus unavailable"
273
+ - "Reverse-DNS naming (be.neatnerds.rosettai)"
274
+ testing: rspec with D-Bus service unit tests, compositor adapter mock
275
+ scenarios, focus monitor event subscription, SNI interface validation,
276
+ graceful degradation tests, and dogtail integration tests for GUI variants
277
+ gems:
278
+ - ruby-dbus
279
+ - i3ipc (sway/i3 focus adapter)
280
+ - gtk4 (rosett-ai-gtk4 package only)
281
+ - adwaita (rosett-ai-gtk4 package only)
282
+ kde_build:
283
+ - cmake
284
+ - extra-cmake-modules
285
+ - kf6-kcmutils
286
+ - kf6-ki18n
287
+ - kf6-kcoreaddons
288
+ - qt6-base-dev
289
+ - qt6-declarative-dev
@@ -0,0 +1,216 @@
1
+ ---
2
+ name: distribution
3
+ domain: ci
4
+ version: 0.2.0
5
+ status: implemented
6
+ priority: 5
7
+ author: claude
8
+ created_at: "2026-02-22"
9
+ modified_at: "2026-03-16"
10
+ modified_by: claude
11
+ depends_on:
12
+ - ci_pipeline
13
+ - release_management
14
+ - documentation
15
+ - security
16
+ - error_handling
17
+
18
+ intent: |
19
+ Define how built packages reach end users through a self-hosted,
20
+ multi-format repository backed by Pulp (pulpproject.org).
21
+
22
+ The build pipeline (P1 ci_pipeline) already produces .deb packages, and
23
+ the release process (P5 release_management) creates versioned tags. This
24
+ document closes the gap: how does a tagged release become an installable
25
+ package for users — and how does that scale to multiple distributions and
26
+ operating systems?
27
+
28
+ Without distribution:
29
+ - Users must manually download .deb files from GitLab releases
30
+ - No automatic security updates via apt upgrade / dnf upgrade
31
+ - No GPG verification of package authenticity
32
+ - No separation between stable and development channels
33
+ - Adding RPM or other formats requires standing up a new tool each time
34
+
35
+ With distribution:
36
+ - Users add the NeatNerds repo once, then 'apt install rosett-ai' or 'dnf install rosett-ai'
37
+ - Security updates arrive via the native package manager
38
+ - Every package is GPG-signed and verifiable
39
+ - Stable and unstable channels serve different audiences
40
+ - New formats (RPM, generic, container, Homebrew tap) are added as Pulp
41
+ plugins without replacing the core infrastructure
42
+
43
+ Why Pulp over aptly:
44
+ - aptly is Debian-only. Pulp supports DEB, RPM, Python, Container, Ansible,
45
+ and generic file repositories via its plugin architecture
46
+ - Pulp is used in production by Microsoft (packages.microsoft.com) and
47
+ Red Hat (Satellite/Katello)
48
+ - Adding RPM support later is 'pulp_rpm plugin install', not 'deploy a
49
+ second repository server'
50
+ - Pulp's REST API is CI-friendly for automated publishing
51
+
52
+ Deployment phases:
53
+ Phase 1 — DEB only (Debian Bookworm, amd64 + arm64). Pulp with pulp_deb.
54
+ Phase 2 — Add RPM (Fedora/RHEL). Install pulp_rpm plugin, add CI matrix.
55
+ Phase 3 — Generic files (AppImage, standalone tarballs). Install pulp_file.
56
+
57
+ Phase 1 is the scope of this design document. Phases 2-3 are noted in
58
+ constraints and acceptance criteria to ensure Phase 1 decisions do not
59
+ block them.
60
+
61
+ CI/CD recipes are documented as reusable pipeline patterns: multi-format
62
+ builds (DEB for amd64 and arm64 in parallel), release automation (tag →
63
+ build → sign → publish → smoke test), and integration test recipes (install
64
+ package in clean container, verify rosett-ai version, verify rai doctor passes).
65
+ These recipes are documented in doc/CI_CD_RECIPES.md and implemented as
66
+ CI job templates in the shared ci-components repository.
67
+
68
+ Distribution complements release management (release_management.yml):
69
+ release management creates versioned tags and changelogs, distribution
70
+ delivers the built packages to end users via native package managers.
71
+ The handoff point is the CI tag event — release creates the tag,
72
+ distribution publishes the artifact.
73
+
74
+ constraints:
75
+ - Package repository managed by Pulp 3 (pulpproject.org) with OCI container deployment
76
+ - DEB support via pulp_deb plugin (Phase 1)
77
+ - RPM support via pulp_rpm plugin MUST NOT be blocked by Phase 1 infrastructure decisions (Phase 2 readiness)
78
+ - Generic file support via pulp_file MUST NOT be blocked (Phase 3 readiness)
79
+ - All packages are GPG-signed using repository-level detached signing (InRelease for DEB, repomd.xml.asc for RPM)
80
+ - GPG signing key uses Ed25519 or RSA-4096 with SHA256+ digest (SHA1 rejected by apt after Feb 2026)
81
+ - CI publishes packages only on annotated tag push events (never on branch commits to stable)
82
+ - Two distribution channels — stable (tagged releases) and unstable (main branch builds)
83
+ - The GPG public key is distributed via HTTPS from the repository server
84
+ - Repository configuration documented in INSTALL.md
85
+ - Package publishing is idempotent — re-publishing the same version is a no-op, not an error
86
+ - The private GPG signing key is stored as a CI/CD variable (protected, masked) — never in the repository
87
+ - Repository serves amd64 and arm64 architectures (DEB Phase 1); x86_64 and aarch64 (RPM Phase 2)
88
+ - HTTPS only for repository access (no plain HTTP)
89
+ - Pulp deployment uses the official OCI images (pulp/pulp-minimal or pulp/pulp)
90
+ - Pulp API access from CI uses token authentication (not username/password)
91
+ - Repository metadata is generated by Pulp (never manually crafted)
92
+ - Infrastructure configuration is reproducible (container compose file versioned in a separate ops repository)
93
+ - "doc/CI_CD_RECIPES.md must document reusable pipeline patterns for
94
+ multi-format builds, release automation, and integration testing"
95
+ - "CI/CD recipes must be engine-agnostic — applicable to any engine that
96
+ produces a distributable artifact"
97
+ - "This design governs package distribution (delivering built packages to
98
+ users). Release management (versioning, tagging, changelogs) is governed
99
+ by release_management.yml. Package building is governed by ci_pipeline.yml.
100
+ The CI tag event is the handoff point between release and distribution"
101
+
102
+ acceptance_criteria:
103
+ - A GitLab CI job deploy:publish runs on tag push and publishes the .deb to the Pulp DEB repository
104
+ - apt install rosett-ai works after adding the NeatNerds repository and GPG key
105
+ - apt upgrade picks up new rosett-ai versions when published to stable
106
+ - Repository serves signed InRelease files verifiable by apt
107
+ - CI job uses Pulp REST API (via pulp-cli or curl) to upload package and trigger publication
108
+ - GPG public key downloadable via HTTPS at a documented URL
109
+ - INSTALL.md contains copy-pasteable commands for repository setup (DEB)
110
+ - Stable channel only receives packages from annotated tags matching v*.*.*
111
+ - Unstable channel receives packages from main branch CI builds (latest commit)
112
+ - Repository supports both amd64 and arm64 packages in the same DEB distribution
113
+ - Pulp container deployment is defined in a docker-compose.yml (or podman equivalent)
114
+ - pulp_rpm plugin can be added to the running Pulp instance without rebuilding (Phase 2 readiness)
115
+ - A CI smoke test verifies the published package is installable in a clean Debian container
116
+ - "CI publish job exits 0 on success, 1 on upload failure, 2 on
117
+ authentication failure, 3 on package validation failure"
118
+ - "doc/CI_CD_RECIPES.md documents multi-format build, release automation,
119
+ and integration test pipeline patterns"
120
+
121
+ examples:
122
+ - scenario: "CI publishes v0.2.0 after tag push"
123
+ expected: |
124
+ 1. Developer pushes tag v0.2.0
125
+ 2. CI pipeline triggers on tag event
126
+ 3. build:package jobs produce rosett-ai_0.2.0_amd64.deb and rosett-ai_0.2.0_arm64.deb
127
+ 4. deploy:publish job authenticates to Pulp API via token
128
+ 5. Job uploads .deb artifacts to Pulp content endpoint
129
+ 6. Job adds packages to the 'stable' DEB repository
130
+ 7. Job triggers Pulp publication (regenerates InRelease, Packages.gz)
131
+ 8. Users see update via 'apt update && apt list --upgradable'
132
+ not: |
133
+ Publishing happens on every commit. Publishing overwrites existing
134
+ version without warning. Publishing uses unsigned repository.
135
+ CI SSHes directly to a server (use API instead).
136
+
137
+ - scenario: "User adds NeatNerds APT repository for the first time"
138
+ expected: |
139
+ # Commands from INSTALL.md:
140
+ curl -fsSL https://repo.neatnerds.be/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/neatnerds.gpg
141
+ echo "deb [signed-by=/usr/share/keyrings/neatnerds.gpg] https://repo.neatnerds.be/stable bookworm main" \
142
+ | sudo tee /etc/apt/sources.list.d/neatnerds.list
143
+ sudo apt update
144
+ sudo apt install rosett-ai
145
+ raictl version # → rai version 0.2.0
146
+ not: |
147
+ Using deprecated apt-key add. Downloading GPG key over HTTP.
148
+ Using unsigned repository. Instructions that don't work on copy-paste.
149
+
150
+ - scenario: "Attempting to publish without API credentials"
151
+ expected: |
152
+ CI job fails with clear error: "Pulp API token not configured.
153
+ Set CI variable PULP_API_TOKEN (protected, masked)."
154
+ No package is published. Pipeline status: failed.
155
+ not: |
156
+ Publish unsigned package to repository. Silently skip authentication.
157
+ Fall back to anonymous upload.
158
+
159
+ - scenario: "Phase 2 — adding RPM support"
160
+ expected: |
161
+ 1. Ops installs pulp_rpm plugin into the running Pulp container
162
+ 2. CI matrix adds Fedora/RHEL build jobs producing .rpm files
163
+ 3. deploy:publish job extended with RPM upload path
164
+ 4. Users on Fedora: dnf config-manager --add-repo https://repo.neatnerds.be/stable/rpm
165
+ 5. Same GPG key, same server, same CI pipeline structure
166
+ not: |
167
+ Standing up a second repository server. Migrating from Pulp to
168
+ another tool. Changing the DEB pipeline to accommodate RPM.
169
+
170
+ anti_patterns:
171
+ - Publishing packages on every commit (stable channel is for releases only)
172
+ - Using apt-key add (deprecated since Debian 11, removed in Debian 12)
173
+ - Distributing GPG key over plain HTTP (MITM risk)
174
+ - Storing GPG private key in the git repository
175
+ - Using SHA1-based GPG keys (rejected by apt after Feb 2026)
176
+ - Manual package uploading to the repository server (must be CI-automated)
177
+ - Mixing stable and unstable packages in the same repository component
178
+ - Publishing without verifying the package installs correctly (smoke test)
179
+ - Using aptly or other Debian-only tools that block future RPM/generic expansion
180
+ - SSHing to the repository server from CI (use Pulp REST API instead)
181
+ - Running Pulp on bare metal without containerisation (reproducibility risk)
182
+ - Crafting repository metadata manually instead of letting Pulp generate it
183
+ #
184
+ gui_notes: |
185
+ Document interactions (cross-references):
186
+
187
+ 1. release_management.yml: release creates versioned tags and changelogs.
188
+ Distribution publishes the built packages. Tag event is the handoff.
189
+
190
+ 2. ci_pipeline.yml: CI builds the packages. Distribution publishes them.
191
+ The publish job runs after the build job in the same pipeline.
192
+
193
+ 3. security.yml: GPG signing, HTTPS transport, token authentication,
194
+ private key storage as CI/CD variable.
195
+
196
+ 4. documentation.yml: INSTALL.md contains repository setup instructions
197
+ that must be kept in sync with distribution changes.
198
+
199
+ 5. error_handling.yml: CI job exit codes follow structured error conventions.
200
+ #
201
+ preferences:
202
+ language: bash
203
+ patterns:
204
+ - "Immutable releases (publish once, never overwrite)"
205
+ - "Signed artifacts (GPG-signed packages and repository metadata)"
206
+ - "Infrastructure as code (container compose versioned in ops repo)"
207
+ - "Plugin architecture (Pulp plugins for format expansion)"
208
+ tools:
209
+ repository: pulp (pulpproject.org)
210
+ plugins_phase1: pulp_deb
211
+ plugins_phase2: pulp_rpm
212
+ plugins_phase3: pulp_file
213
+ signing: gpg (Ed25519 or RSA-4096, SHA256+)
214
+ transport: pulp REST API over HTTPS
215
+ deployment: OCI containers (docker-compose or podman)
216
+ ci: gitlab-ci with protected variables