rosett-ai 1.3.3 → 1.5.9

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 (453) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +398 -22
  3. data/README.md +56 -42
  4. data/bin/raictl +13 -0
  5. data/conf/adopt_redactions.yml +2 -0
  6. data/conf/compliance/cra_rules.yml +2 -0
  7. data/conf/compliance/license_rules.yml +2 -0
  8. data/conf/mcp/server_defaults.yml +2 -0
  9. data/conf/mcp/trust.yml +1 -0
  10. data/conf/packaging/core.yml +2 -0
  11. data/conf/packaging/gtk4.yml +2 -0
  12. data/conf/packaging/qt6.yml +2 -0
  13. data/conf/policy/default_deny_list.yml +2 -0
  14. data/conf/review/cli-command-audit.yml +2 -0
  15. data/conf/review/design-docs.yml +2 -0
  16. data/conf/review/design-questionnaire.yml +2 -0
  17. data/conf/review/questionnaire.yml +2 -0
  18. data/conf/review/rosett-ai-core.yml +2 -0
  19. data/conf/schemas/ai_config_schema.json +14 -2
  20. data/conf/schemas/autoqueue.schema.json +153 -0
  21. data/conf/schemas/behaviour_schema.json +31 -7
  22. data/conf/schemas/compliance_rule_schema.json +17 -4
  23. data/conf/schemas/content_pack_manifest_schema.json +23 -4
  24. data/conf/schemas/design_schema.json +177 -42
  25. data/conf/schemas/engine_manifest_schema.json +22 -5
  26. data/conf/schemas/lockfile_schema.json +26 -4
  27. data/conf/schemas/mcp_server_schema.json +50 -9
  28. data/conf/schemas/packaging_schema.json +23 -5
  29. data/conf/schemas/policy_schema.json +35 -9
  30. data/conf/schemas/provenance_schema.json +33 -5
  31. data/conf/schemas/rai_config_schema.json +6 -2
  32. data/conf/schemas/rai_project_schema.json +8 -2
  33. data/conf/schemas/scope_hierarchy_schema.json +22 -5
  34. data/conf/schemas/target_schema.json +33 -6
  35. data/conf/schemas/tooling_schema.json +53 -12
  36. data/conf/schemas/workflow_schema.json +39 -9
  37. data/conf/targets/agents_md.yml +1 -0
  38. data/conf/targets/claude.yml +2 -0
  39. data/conf/tooling/tools.yml +2 -0
  40. data/lib/rosett_ai/adopter/local_analysis_collector.rb +5 -0
  41. data/lib/rosett_ai/adopter/rule_adopter.rb +40 -0
  42. data/lib/rosett_ai/ai_config/context_window.rb +3 -0
  43. data/lib/rosett_ai/ai_config/cost_controls.rb +1 -0
  44. data/lib/rosett_ai/ai_config/fallback_chain.rb +1 -0
  45. data/lib/rosett_ai/ai_config/model_router.rb +1 -0
  46. data/lib/rosett_ai/ai_config/validator.rb +2 -0
  47. data/lib/rosett_ai/authorship/attribution_compiler.rb +1 -0
  48. data/lib/rosett_ai/authorship/disclosure_policy.rb +2 -0
  49. data/lib/rosett_ai/authorship/review_validator.rb +1 -0
  50. data/lib/rosett_ai/authorship/trailer_generator.rb +1 -0
  51. data/lib/rosett_ai/backup/compressor.rb +3 -0
  52. data/lib/rosett_ai/backup/destination.rb +1 -0
  53. data/lib/rosett_ai/behaviour/manager.rb +1 -0
  54. data/lib/rosett_ai/compiler/backend.rb +3 -0
  55. data/lib/rosett_ai/compiler/backends/agents_md_backend.rb +1 -0
  56. data/lib/rosett_ai/compiler/backends/claude_backend.rb +1 -0
  57. data/lib/rosett_ai/compiler/behaviour_compiler.rb +1 -0
  58. data/lib/rosett_ai/compiler/compilation_pipeline.rb +1 -7
  59. data/lib/rosett_ai/compiler/locale_compiler.rb +2 -0
  60. data/lib/rosett_ai/compiler/target_profile.rb +11 -0
  61. data/lib/rosett_ai/completion/generator.rb +2 -0
  62. data/lib/rosett_ai/completion/shells/zsh_generator.rb +1 -0
  63. data/lib/rosett_ai/comply/checkers/cra_checker.rb +1 -0
  64. data/lib/rosett_ai/comply/checkers/license_checker.rb +2 -0
  65. data/lib/rosett_ai/comply/checkers/spdx_header_checker.rb +4 -0
  66. data/lib/rosett_ai/comply/runner.rb +2 -0
  67. data/lib/rosett_ai/composition/composer.rb +1 -0
  68. data/lib/rosett_ai/composition/lockfile.rb +1 -0
  69. data/lib/rosett_ai/composition/merge_strategy.rb +1 -0
  70. data/lib/rosett_ai/config/masking_secret_resolver.rb +9 -0
  71. data/lib/rosett_ai/config/secret_resolver.rb +4 -0
  72. data/lib/rosett_ai/configuration.rb +4 -0
  73. data/lib/rosett_ai/content/content_client.rb +15 -0
  74. data/lib/rosett_ai/content/pack_installer.rb +1 -0
  75. data/lib/rosett_ai/content/pack_manifest.rb +21 -0
  76. data/lib/rosett_ai/content_packs/manager.rb +1 -0
  77. data/lib/rosett_ai/dbus/compositor_detector.rb +2 -0
  78. data/lib/rosett_ai/dbus/focus_adapters/base.rb +1 -0
  79. data/lib/rosett_ai/dbus/focus_adapters/gnome_adapter.rb +5 -0
  80. data/lib/rosett_ai/dbus/focus_adapters/hyprland_adapter.rb +4 -0
  81. data/lib/rosett_ai/dbus/focus_adapters/i3_adapter.rb +4 -0
  82. data/lib/rosett_ai/dbus/focus_adapters/kwin_adapter.rb +4 -0
  83. data/lib/rosett_ai/dbus/focus_adapters/x11_adapter.rb +4 -0
  84. data/lib/rosett_ai/dbus/focus_monitor_interface.rb +1 -0
  85. data/lib/rosett_ai/dbus/manager_interface.rb +1 -0
  86. data/lib/rosett_ai/dbus/plugin_manager_interface.rb +2 -0
  87. data/lib/rosett_ai/dbus/rate_limiter.rb +1 -0
  88. data/lib/rosett_ai/dbus/service.rb +3 -0
  89. data/lib/rosett_ai/dbus/status_notifier_interface.rb +14 -0
  90. data/lib/rosett_ai/desktop/dbus_client.rb +6 -0
  91. data/lib/rosett_ai/desktop/gtk4_app.rb +3 -0
  92. data/lib/rosett_ai/desktop/gtk4_preferences.rb +1 -0
  93. data/lib/rosett_ai/desktop/gui_logger.rb +2 -0
  94. data/lib/rosett_ai/doctor/check.rb +1 -1
  95. data/lib/rosett_ai/doctor/checks/cache_health_check.rb +1 -0
  96. data/lib/rosett_ai/doctor.rb +1 -0
  97. data/lib/rosett_ai/documentation/reference_compiler.rb +9 -0
  98. data/lib/rosett_ai/documentation/translator.rb +8 -0
  99. data/lib/rosett_ai/engines/base_config_compiler.rb +71 -1
  100. data/lib/rosett_ai/engines/detector.rb +5 -0
  101. data/lib/rosett_ai/engines/registry.rb +7 -0
  102. data/lib/rosett_ai/exit_codes.rb +6 -0
  103. data/lib/rosett_ai/formatting.rb +1 -0
  104. data/lib/rosett_ai/gem_consistency_checker.rb +6 -0
  105. data/lib/rosett_ai/git_hooks/chain_detector.rb +1 -0
  106. data/lib/rosett_ai/git_hooks/installer.rb +4 -0
  107. data/lib/rosett_ai/git_hooks/script_generator.rb +2 -0
  108. data/lib/rosett_ai/gitlab/validators/supplementary_gitlab_ci_yaml_validator.rb +6 -0
  109. data/lib/rosett_ai/i18n/utf8_checker.rb +1 -0
  110. data/lib/rosett_ai/init/config_file_writer.rb +4 -0
  111. data/lib/rosett_ai/init/directory_builder.rb +15 -0
  112. data/lib/rosett_ai/init/file_copier.rb +51 -0
  113. data/lib/rosett_ai/init/mcp_registrar.rb +1 -0
  114. data/lib/rosett_ai/init/project_initializer.rb +1 -0
  115. data/lib/rosett_ai/licensing/license_key.rb +4 -0
  116. data/lib/rosett_ai/licensing/license_store.rb +11 -0
  117. data/lib/rosett_ai/licensing/tier.rb +9 -0
  118. data/lib/rosett_ai/mcp/admin/auditor.rb +1 -0
  119. data/lib/rosett_ai/mcp/admin/health_checker.rb +1 -0
  120. data/lib/rosett_ai/mcp/admin/registry.rb +1 -0
  121. data/lib/rosett_ai/mcp/enforcement/hook_generator.rb +27 -4
  122. data/lib/rosett_ai/mcp/enforcement/validator.rb +24 -3
  123. data/lib/rosett_ai/mcp/governance.rb +9 -0
  124. data/lib/rosett_ai/mcp/http_security_config.rb +22 -0
  125. data/lib/rosett_ai/mcp/key_hasher.rb +4 -2
  126. data/lib/rosett_ai/mcp/keyfile.rb +4 -0
  127. data/lib/rosett_ai/mcp/middleware/cors.rb +4 -0
  128. data/lib/rosett_ai/mcp/middleware/origin_validation.rb +1 -0
  129. data/lib/rosett_ai/mcp/middleware/rate_limit.rb +3 -0
  130. data/lib/rosett_ai/mcp/plugins.rb +1 -0
  131. data/lib/rosett_ai/mcp/prompts/compilation_prompt.rb +2 -0
  132. data/lib/rosett_ai/mcp/prompts/compliance_prompt.rb +3 -0
  133. data/lib/rosett_ai/mcp/prompts/diagnostics_prompt.rb +2 -0
  134. data/lib/rosett_ai/mcp/prompts/validation_prompt.rb +2 -0
  135. data/lib/rosett_ai/mcp/resources/behaviour_resource.rb +2 -0
  136. data/lib/rosett_ai/mcp/resources/config_resource.rb +2 -0
  137. data/lib/rosett_ai/mcp/resources/design_resource.rb +1 -0
  138. data/lib/rosett_ai/mcp/resources/hooks_resource.rb +3 -0
  139. data/lib/rosett_ai/mcp/resources/provenance_resource.rb +2 -0
  140. data/lib/rosett_ai/mcp/resources/rules_resource.rb +1 -0
  141. data/lib/rosett_ai/mcp/resources/schema_resource.rb +1 -0
  142. data/lib/rosett_ai/mcp/server.rb +7 -1
  143. data/lib/rosett_ai/mcp/settings/trust_manager.rb +3 -0
  144. data/lib/rosett_ai/mcp/tools/adopt_tool.rb +4 -0
  145. data/lib/rosett_ai/mcp/tools/backup_tool.rb +4 -0
  146. data/lib/rosett_ai/mcp/tools/behaviour_display_tool.rb +4 -0
  147. data/lib/rosett_ai/mcp/tools/behaviour_list_tool.rb +3 -0
  148. data/lib/rosett_ai/mcp/tools/behaviour_manage_tool.rb +5 -0
  149. data/lib/rosett_ai/mcp/tools/behaviour_show_tool.rb +4 -0
  150. data/lib/rosett_ai/mcp/tools/compile_status_tool.rb +4 -0
  151. data/lib/rosett_ai/mcp/tools/compile_tool.rb +4 -0
  152. data/lib/rosett_ai/mcp/tools/comply_tool.rb +4 -0
  153. data/lib/rosett_ai/mcp/tools/config_compile_tool.rb +4 -0
  154. data/lib/rosett_ai/mcp/tools/config_status_tool.rb +3 -0
  155. data/lib/rosett_ai/mcp/tools/content_tool.rb +5 -0
  156. data/lib/rosett_ai/mcp/tools/context_query_tool.rb +4 -0
  157. data/lib/rosett_ai/mcp/tools/design_list_tool.rb +3 -0
  158. data/lib/rosett_ai/mcp/tools/design_show_tool.rb +4 -0
  159. data/lib/rosett_ai/mcp/tools/doctor_tool.rb +4 -0
  160. data/lib/rosett_ai/mcp/tools/documentation_status_tool.rb +3 -0
  161. data/lib/rosett_ai/mcp/tools/engines_tool.rb +5 -0
  162. data/lib/rosett_ai/mcp/tools/hook_install_tool.rb +7 -0
  163. data/lib/rosett_ai/mcp/tools/hook_preview_tool.rb +33 -8
  164. data/lib/rosett_ai/mcp/tools/hooks_status_tool.rb +5 -0
  165. data/lib/rosett_ai/mcp/tools/init_tool.rb +5 -0
  166. data/lib/rosett_ai/mcp/tools/license_status_tool.rb +3 -0
  167. data/lib/rosett_ai/mcp/tools/project_tool.rb +5 -0
  168. data/lib/rosett_ai/mcp/tools/provenance_tool.rb +5 -0
  169. data/lib/rosett_ai/mcp/tools/provenance_write_tool.rb +3 -0
  170. data/lib/rosett_ai/mcp/tools/retrofit_tool.rb +5 -0
  171. data/lib/rosett_ai/mcp/tools/rule_search_tool.rb +4 -0
  172. data/lib/rosett_ai/mcp/tools/schema_get_tool.rb +5 -0
  173. data/lib/rosett_ai/mcp/tools/tooling_tool.rb +5 -0
  174. data/lib/rosett_ai/mcp/tools/validate_tool.rb +4 -0
  175. data/lib/rosett_ai/mcp/tools/workflow_execute_tool.rb +4 -0
  176. data/lib/rosett_ai/mcp/tools/workflow_tool.rb +5 -0
  177. data/lib/rosett_ai/migration/detector.rb +1 -0
  178. data/lib/rosett_ai/migration/nncc_config_migrator.rb +2 -0
  179. data/lib/rosett_ai/migration/xdg_migrator.rb +3 -1
  180. data/lib/rosett_ai/package_manager/apt.rb +5 -0
  181. data/lib/rosett_ai/package_manager/base.rb +1 -0
  182. data/lib/rosett_ai/package_manager/gem_backend.rb +1 -0
  183. data/lib/rosett_ai/packaging/variant_config.rb +12 -0
  184. data/lib/rosett_ai/plugins/contract.rb +1 -0
  185. data/lib/rosett_ai/plugins/engine_contract.rb +2 -0
  186. data/lib/rosett_ai/plugins/gui_contract.rb +2 -0
  187. data/lib/rosett_ai/plugins/mcp_contract.rb +2 -0
  188. data/lib/rosett_ai/plugins/registry.rb +10 -0
  189. data/lib/rosett_ai/policy/auditor.rb +1 -0
  190. data/lib/rosett_ai/policy/opt_out_scanner.rb +1 -0
  191. data/lib/rosett_ai/policy/tier_hierarchy.rb +2 -0
  192. data/lib/rosett_ai/policy/validator.rb +1 -0
  193. data/lib/rosett_ai/profiler.rb +7 -0
  194. data/lib/rosett_ai/project/drift_detector.rb +1 -0
  195. data/lib/rosett_ai/project/manager.rb +1 -0
  196. data/lib/rosett_ai/project/template_applier.rb +1 -0
  197. data/lib/rosett_ai/provenance/entry.rb +2 -0
  198. data/lib/rosett_ai/provenance/source.rb +1 -0
  199. data/lib/rosett_ai/provenance/store.rb +3 -0
  200. data/lib/rosett_ai/provenance/validator.rb +1 -0
  201. data/lib/rosett_ai/quorum/collector.rb +1 -0
  202. data/lib/rosett_ai/quorum/comparator.rb +2 -0
  203. data/lib/rosett_ai/quorum/strategies/adopt.rb +1 -0
  204. data/lib/rosett_ai/rai_config.rb +9 -0
  205. data/lib/rosett_ai/retrofit/engine.rb +2 -0
  206. data/lib/rosett_ai/retrofit/parsers/agents_md_parser.rb +8 -0
  207. data/lib/rosett_ai/retrofit/parsers/claude_parser.rb +10 -0
  208. data/lib/rosett_ai/retrofit/parsers/cursor_parser.rb +9 -0
  209. data/lib/rosett_ai/retrofit/secret_detector.rb +3 -0
  210. data/lib/rosett_ai/secrets_resolver.rb +1 -0
  211. data/lib/rosett_ai/session_hooks/installer.rb +130 -0
  212. data/lib/rosett_ai/smart_feedback/suggester.rb +4 -0
  213. data/lib/rosett_ai/smart_feedback/thor_middleware.rb +7 -0
  214. data/lib/rosett_ai/structured_logger.rb +1 -0
  215. data/lib/rosett_ai/telemetry/log_rotator.rb +1 -0
  216. data/lib/rosett_ai/telemetry.rb +1 -0
  217. data/lib/rosett_ai/thor/cli.rb +9 -0
  218. data/lib/rosett_ai/thor/tasks/adopt.rb +2 -0
  219. data/lib/rosett_ai/thor/tasks/backfill_user_yml.rb +207 -0
  220. data/lib/rosett_ai/thor/tasks/backup.rb +6 -0
  221. data/lib/rosett_ai/thor/tasks/behaviour.rb +12 -0
  222. data/lib/rosett_ai/thor/tasks/build.rb +87 -4
  223. data/lib/rosett_ai/thor/tasks/compile.rb +76 -32
  224. data/lib/rosett_ai/thor/tasks/completion.rb +9 -0
  225. data/lib/rosett_ai/thor/tasks/comply.rb +2 -0
  226. data/lib/rosett_ai/thor/tasks/config.rb +21 -5
  227. data/lib/rosett_ai/thor/tasks/content.rb +8 -0
  228. data/lib/rosett_ai/thor/tasks/dbus.rb +13 -0
  229. data/lib/rosett_ai/thor/tasks/design.rb +2 -0
  230. data/lib/rosett_ai/thor/tasks/desktop.rb +4 -0
  231. data/lib/rosett_ai/thor/tasks/doctor.rb +2 -0
  232. data/lib/rosett_ai/thor/tasks/documentation.rb +7 -0
  233. data/lib/rosett_ai/thor/tasks/engines.rb +8 -0
  234. data/lib/rosett_ai/thor/tasks/hooks.rb +8 -0
  235. data/lib/rosett_ai/thor/tasks/init.rb +1 -0
  236. data/lib/rosett_ai/thor/tasks/license.rb +8 -0
  237. data/lib/rosett_ai/thor/tasks/mcp.rb +40 -0
  238. data/lib/rosett_ai/thor/tasks/migrate.rb +2 -0
  239. data/lib/rosett_ai/thor/tasks/plugins.rb +15 -0
  240. data/lib/rosett_ai/thor/tasks/project.rb +8 -0
  241. data/lib/rosett_ai/thor/tasks/provenance.rb +8 -0
  242. data/lib/rosett_ai/thor/tasks/release.rb +8 -0
  243. data/lib/rosett_ai/thor/tasks/retrofit.rb +4 -0
  244. data/lib/rosett_ai/thor/tasks/validate.rb +1 -0
  245. data/lib/rosett_ai/thor/tasks/workflow.rb +14 -0
  246. data/lib/rosett_ai/tooling/version_checker.rb +1 -0
  247. data/lib/rosett_ai/ui/accessible_tui.rb +18 -0
  248. data/lib/rosett_ai/ui/base.rb +3 -0
  249. data/lib/rosett_ai/ui/gtk4.rb +19 -0
  250. data/lib/rosett_ai/ui/kde.rb +1 -0
  251. data/lib/rosett_ai/ui/qt6.rb +1 -0
  252. data/lib/rosett_ai/ui/registry.rb +15 -0
  253. data/lib/rosett_ai/ui/tui.rb +22 -0
  254. data/lib/rosett_ai/validators/behaviour_validator.rb +1 -0
  255. data/lib/rosett_ai/validators/design_validator.rb +2 -0
  256. data/lib/rosett_ai/validators/schema_validator.rb +4 -0
  257. data/lib/rosett_ai/validators/tooling_validator.rb +1 -0
  258. data/lib/rosett_ai/version.rb +2 -1
  259. data/lib/rosett_ai/version_consistency_checker.rb +6 -0
  260. data/lib/rosett_ai/workflow/engine.rb +1 -0
  261. data/lib/rosett_ai/workflow/manager.rb +1 -0
  262. data/lib/rosett_ai/workflow/schema_validator.rb +2 -0
  263. data/lib/rosett_ai/workflow/step_runner.rb +1 -0
  264. data/lib/rosett_ai/workflow/steps/rai_step.rb +1 -0
  265. data/lib/rosett_ai/yaml_loader.rb +2 -0
  266. data/lib/rosett_ai.rb +2 -0
  267. data/lib/scripts/generated/docker_hub_tags.rb +2 -0
  268. data/locales/ar.yml +2 -0
  269. data/locales/en.yml +5 -0
  270. data/locales/fr.yml +2 -0
  271. metadata +9 -189
  272. data/.ai-provenance.yml +0 -119
  273. data/.debride_whitelist +0 -186
  274. data/.fasterer.yml +0 -29
  275. data/.mdl_style.rb +0 -10
  276. data/.mdlrc +0 -3
  277. data/.mutant.yml +0 -49
  278. data/.namespace-allowlist +0 -42
  279. data/.reek.yml +0 -1040
  280. data/.rosett-ai/config.yml +0 -3
  281. data/.rspec +0 -5
  282. data/.rubocop.yml +0 -380
  283. data/.ruby-version +0 -1
  284. data/.yamllint +0 -51
  285. data/.yardopts +0 -12
  286. data/AI-DISCLOSURE.md +0 -48
  287. data/CLAUDE.md +0 -141
  288. data/CONTRIBUTING.md +0 -734
  289. data/INSTALL.md +0 -154
  290. data/LICENSE.md +0 -675
  291. data/QUICKSTART.md +0 -73
  292. data/Rakefile +0 -200
  293. data/SECURITY.md +0 -114
  294. data/cliff.toml +0 -52
  295. data/conf/behaviour/.gitkeep +0 -0
  296. data/conf/design/aaif_alignment.yml +0 -181
  297. data/conf/design/ab_testing.yml +0 -172
  298. data/conf/design/accessibility.yml +0 -84
  299. data/conf/design/ai_authorship.yml +0 -210
  300. data/conf/design/ai_provenance.yml +0 -224
  301. data/conf/design/ai_tool_configuration.yml +0 -207
  302. data/conf/design/architecture.yml +0 -139
  303. data/conf/design/autocompletion.yml +0 -115
  304. data/conf/design/backward_compatibility.yml +0 -112
  305. data/conf/design/behaviour_composition.yml +0 -246
  306. data/conf/design/build_rake_extraction.yml +0 -57
  307. data/conf/design/ci_pipeline.yml +0 -100
  308. data/conf/design/claude_code_configuration.yml +0 -157
  309. data/conf/design/compiler.yml +0 -128
  310. data/conf/design/comply.yml +0 -153
  311. data/conf/design/content_packs.yml +0 -84
  312. data/conf/design/desktop_integration.yml +0 -289
  313. data/conf/design/distribution.yml +0 -216
  314. data/conf/design/doctor.yml +0 -184
  315. data/conf/design/documentation.yml +0 -152
  316. data/conf/design/engine_architecture.yml +0 -257
  317. data/conf/design/error_handling.yml +0 -103
  318. data/conf/design/feature_flags.yml +0 -142
  319. data/conf/design/git_hooks.yml +0 -165
  320. data/conf/design/gui_plugins.yml +0 -475
  321. data/conf/design/i18n.yml +0 -84
  322. data/conf/design/integration_testing.yml +0 -56
  323. data/conf/design/licensing_system.yml +0 -88
  324. data/conf/design/lifecycle_management.yml +0 -208
  325. data/conf/design/mcp_integration.yml +0 -207
  326. data/conf/design/mcp_settings.yml +0 -126
  327. data/conf/design/migration.yml +0 -56
  328. data/conf/design/monitoring_observability.yml +0 -194
  329. data/conf/design/namespace_cleanup.yml +0 -145
  330. data/conf/design/plugin_test_segregation.yml +0 -145
  331. data/conf/design/policy_management.yml +0 -229
  332. data/conf/design/project_management.yml +0 -183
  333. data/conf/design/rai_mcp_asset_discovery.yml +0 -164
  334. data/conf/design/rai_mcp_server.yml +0 -605
  335. data/conf/design/release_management.yml +0 -117
  336. data/conf/design/retrofit.yml +0 -199
  337. data/conf/design/retrospective_analyzer.yml +0 -79
  338. data/conf/design/scope_hierarchy.yml +0 -352
  339. data/conf/design/security.yml +0 -115
  340. data/conf/design/session_retrospective.yml +0 -85
  341. data/conf/design/smart_ui_feedback.yml +0 -89
  342. data/conf/design/structured_logging.yml +0 -148
  343. data/conf/design/styles.yml +0 -123
  344. data/conf/design/test_peer_review.yml +0 -89
  345. data/conf/design/testing.yml +0 -136
  346. data/conf/design/threat_model.yml +0 -108
  347. data/conf/design/ui_framework.yml +0 -111
  348. data/conf/design/usage_optimization.yml +0 -122
  349. data/conf/design/version_management.yml +0 -60
  350. data/conf/design/workflow.yml +0 -227
  351. data/doc/AAIF_POSITIONING.md +0 -58
  352. data/doc/ADOPT.md +0 -224
  353. data/doc/AI_PROVENANCE.md +0 -139
  354. data/doc/ARCHITECTURE.md +0 -920
  355. data/doc/BEHAVIOUR.md +0 -409
  356. data/doc/BUILD.md +0 -138
  357. data/doc/CI_CD_RECIPES.md +0 -171
  358. data/doc/CLAUDE_SESSIONS_MOVED.md +0 -16
  359. data/doc/COMMAND_ANALYSIS.md +0 -229
  360. data/doc/CONFIGURATION.md +0 -281
  361. data/doc/DESIGN_AUDIT.md +0 -235
  362. data/doc/DESIGN_PEER_REVIEW.md +0 -771
  363. data/doc/DESKTOP.md +0 -447
  364. data/doc/ENGINES.md +0 -567
  365. data/doc/ENGINE_DEVELOPMENT_GUIDE.md +0 -417
  366. data/doc/FEATURE_AUDIT.md +0 -218
  367. data/doc/IMPLEMENTATION_PLAN.md +0 -669
  368. data/doc/INCIDENT_REPORT_2026-02-02.md +0 -251
  369. data/doc/MIGRATION_GUIDE.md +0 -88
  370. data/doc/PACKAGING.md +0 -232
  371. data/doc/PROJECT_DASHBOARD.md +0 -153
  372. data/doc/PULP_DEPLOYMENT.md +0 -164
  373. data/doc/QUALITY_FIX_SUMMARY.md +0 -110
  374. data/doc/QUICK_START.md +0 -162
  375. data/doc/REEK_CONFIGURATION.md +0 -166
  376. data/doc/REFERENCE.md +0 -253
  377. data/doc/REFERENCES.md +0 -324
  378. data/doc/SECURITY_REVIEW_CHECKLIST.md +0 -72
  379. data/doc/SESSION_2026-02-28_GTK4_HARDENING.md +0 -359
  380. data/doc/SETUP.md +0 -202
  381. data/doc/TEST_PEER_REVIEW.md +0 -152
  382. data/doc/THREAT_MODEL.md +0 -230
  383. data/doc/USAGE.md +0 -545
  384. data/doc/USER_MANUAL.md +0 -585
  385. data/doc/ai_test_review_checklist.md +0 -110
  386. data/doc/changes/2026-02-18-packaging-fpm.md +0 -155
  387. data/doc/changes/2026-02-19-testing-infrastructure.md +0 -221
  388. data/doc/changes/2026-02-20-security-implementation.md +0 -281
  389. data/doc/changes/2026-02-20-styles-implementation.md +0 -220
  390. data/doc/changes/2026-02-21-architecture-completion.md +0 -95
  391. data/doc/changes/2026-02-21-architecture-ui-layer.md +0 -253
  392. data/doc/changes/2026-02-21-cc-config-implementation.md +0 -108
  393. data/doc/changes/2026-02-21-ci-pipeline-implementation.md +0 -214
  394. data/doc/changes/2026-02-21-compiler-multi-target-pipeline.md +0 -241
  395. data/doc/changes/2026-02-21-config-design-show-commands.md +0 -61
  396. data/doc/changes/2026-02-21-design-implementation-overview.md +0 -455
  397. data/doc/changes/2026-02-21-lifecycle-management.md +0 -196
  398. data/doc/changes/2026-02-21-path-resolver.md +0 -128
  399. data/doc/changes/2026-02-24-ci-tmpdir-mutant-fetch.md +0 -45
  400. data/doc/changes/2026-03-01-ci-bundler-strategy.md +0 -120
  401. data/doc/changes/2026-03-20-security-hardening-phase2.md +0 -163
  402. data/doc/context/SESSION-HANDOFF.md +0 -69
  403. data/doc/context/ai-engine-usage-trends-2026.md +0 -80
  404. data/doc/context/plan-pluggable-engines.md +0 -590
  405. data/doc/decisions/001-flog-deferred.md +0 -32
  406. data/doc/decisions/002-path-resolution-strategy.md +0 -158
  407. data/doc/decisions/003-ui-adapter-selection.md +0 -193
  408. data/doc/decisions/004-design-document-validation.md +0 -179
  409. data/doc/decisions/005-package-splitting-strategy.md +0 -200
  410. data/doc/decisions/006-multi-engine-architecture.md +0 -147
  411. data/doc/decisions/007-engine-agnostic-pivot.md +0 -219
  412. data/doc/decisions/008-ci-bundler-strategy.md +0 -129
  413. data/doc/decisions/009-core-only-v1-release.md +0 -60
  414. data/doc/decisions/010-engine-debian-packaging.md +0 -66
  415. data/doc/decisions/011-context-aware-cli.md +0 -71
  416. data/doc/dependency_decisions.yml +0 -247
  417. data/doc/issues/001-wrapper-missing-environment-variables.md +0 -197
  418. data/doc/issues/002-embedded-ruby-wrong-prefix.md +0 -217
  419. data/doc/issues/003-smoke-test-false-positive.md +0 -127
  420. data/doc/issues/004-market-research-design-updates.md +0 -109
  421. data/doc/issues/005-compile-scope-coexistence.md +0 -161
  422. data/doc/locales/.gitkeep +0 -0
  423. data/doc/man/rai.1.ronn +0 -505
  424. data/doc/operations/packaging.md +0 -133
  425. data/doc/operations/rosett-ai-release.md +0 -65
  426. data/doc/reference/error-catalog.md +0 -107
  427. data/doc/reference/rosett-ai-technical-reference.pdf +0 -0
  428. data/doc/reference/src/Pictures/cover.jpg +0 -0
  429. data/doc/reference/src/Pictures/head1.jpg +0 -0
  430. data/doc/reference/src/Pictures/head2.jpg +0 -0
  431. data/doc/reference/src/Pictures/head3.jpg +0 -0
  432. data/doc/reference/src/Pictures/head4.jpg +0 -0
  433. data/doc/reference/src/Pictures/head5.jpg +0 -0
  434. data/doc/reference/src/Pictures/head6.jpg +0 -0
  435. data/doc/reference/src/Pictures/head7.jpg +0 -0
  436. data/doc/reference/src/Pictures/head8.jpg +0 -0
  437. data/doc/reference/src/StyleInd.ist +0 -4
  438. data/doc/reference/src/bibliography.bib +0 -79
  439. data/doc/reference/src/main.tex +0 -1288
  440. data/doc/reference/src/structure.tex +0 -303
  441. data/doc/rosett-ai-bookmarks.html +0 -301
  442. data/kitchen.yml +0 -46
  443. data/lib/rosett_ai/mcp/enforcement/.gitkeep +0 -0
  444. data/locales/.gitkeep +0 -0
  445. data/packaging/build-engine-deb.sh +0 -81
  446. data/packaging/scripts/postinst +0 -17
  447. data/packaging/scripts/postrm +0 -19
  448. data/packaging/scripts/prerm +0 -10
  449. data/packaging/wrapper.sh.template +0 -38
  450. data/rosett-ai.gemspec +0 -63
  451. data/rules/.gitkeep +0 -0
  452. data/scripts/publish/pulp_upload.sh +0 -123
  453. data/settings.json +0 -29
@@ -14,10 +14,14 @@ module RosettAi
14
14
  # @author hugo
15
15
  # @author claude
16
16
  class AgentsMdParser < BaseParser
17
+ # Return the engine identifier string.
18
+ # @return [String]
17
19
  def engine_name
18
20
  'agents_md'
19
21
  end
20
22
 
23
+ # Discover native config files for this engine.
24
+ # @return [Array<String>]
21
25
  def discover
22
26
  project_root = Pathname.new(ENV.fetch('RAI_ORIGINAL_PWD', Dir.pwd))
23
27
  agents_md = project_root.join('AGENTS.md')
@@ -27,6 +31,10 @@ module RosettAi
27
31
  []
28
32
  end
29
33
 
34
+ # Parse a native config file into rosett-ai format.
35
+ #
36
+ # @param path [Object] the path
37
+ # @return [Hash]
30
38
  def parse(path)
31
39
  validate_path!(path)
32
40
  content = File.read(path)
@@ -7,6 +7,7 @@ require 'json'
7
7
 
8
8
  module RosettAi
9
9
  module Retrofit
10
+ # Engine-specific native config parsers.
10
11
  module Parsers
11
12
  # Retrofit parser for Claude Code configuration files.
12
13
  #
@@ -16,14 +17,19 @@ module RosettAi
16
17
  # @author hugo
17
18
  # @author claude
18
19
  class ClaudeParser < BaseParser
20
+ # @return [Array] Configuration keys recognized by this parser.
19
21
  KNOWN_KEYS = [
20
22
  'permissions', 'allowedTools', 'deniedTools', 'trustedTools', 'env', 'hooks', 'mcpServers', 'customApiKeyResponses', 'contextProviders', 'preferences'
21
23
  ].freeze
22
24
 
25
+ # Return the engine identifier string.
26
+ # @return [String]
23
27
  def engine_name
24
28
  'claude'
25
29
  end
26
30
 
31
+ # Discover native config files for this engine.
32
+ # @return [Array<String>]
27
33
  def discover
28
34
  paths = []
29
35
  global = Pathname.new(Dir.home).join('.claude', 'settings.json')
@@ -35,6 +41,10 @@ module RosettAi
35
41
  paths
36
42
  end
37
43
 
44
+ # Parse a native config file into rosett-ai format.
45
+ #
46
+ # @param path [Object] the path
47
+ # @return [Hash]
38
48
  def parse(path)
39
49
  validate_path!(path)
40
50
  content = File.read(path)
@@ -16,14 +16,19 @@ module RosettAi
16
16
  # @author hugo
17
17
  # @author claude
18
18
  class CursorParser < BaseParser
19
+ # @return [Array] Configuration keys recognized by this parser.
19
20
  KNOWN_KEYS = [
20
21
  'rules', 'model', 'temperature', 'maxTokens', 'contextFiles', 'ignoreFiles'
21
22
  ].freeze
22
23
 
24
+ # Return the engine identifier string.
25
+ # @return [String]
23
26
  def engine_name
24
27
  'cursor'
25
28
  end
26
29
 
30
+ # Discover native config files for this engine.
31
+ # @return [Array<String>]
27
32
  def discover
28
33
  paths = []
29
34
  project_root = Pathname.new(ENV.fetch('RAI_ORIGINAL_PWD', Dir.pwd))
@@ -37,6 +42,10 @@ module RosettAi
37
42
  paths
38
43
  end
39
44
 
45
+ # Parse a native config file into rosett-ai format.
46
+ #
47
+ # @param path [Object] the path
48
+ # @return [Hash]
40
49
  def parse(path)
41
50
  validate_path!(path)
42
51
 
@@ -14,6 +14,7 @@ module RosettAi
14
14
  # @author hugo
15
15
  # @author claude
16
16
  class SecretDetector
17
+ # @return [Array] Regex patterns matching sensitive configuration keys.
17
18
  SENSITIVE_KEY_PATTERNS = [
18
19
  /api[_-]?key/i,
19
20
  /secret/i,
@@ -24,8 +25,10 @@ module RosettAi
24
25
  /private[_-]?key/i
25
26
  ].freeze
26
27
 
28
+ # @return [Array] String prefixes indicating a secret value.
27
29
  SECRET_VALUE_PREFIXES = ['sk-', 'pk-', 'ghp_', 'gho_', 'ghs_', 'github_pat_', 'xoxb-', 'xoxp-'].freeze
28
30
 
31
+ # @return [Integer] Minimum string length to consider as a potential secret.
29
32
  MIN_SECRET_LENGTH = 20
30
33
 
31
34
  # @param warnings [Array<String>] mutable array for warning messages
@@ -8,6 +8,7 @@ module RosettAi
8
8
  # Resolution order: ENV variable > secrets file (0600).
9
9
  # System keyring support planned for GUI phase (P3).
10
10
  module SecretsResolver
11
+ # @return [Object] File permission mode for secrets files.
11
12
  SAFE_PERMISSIONS = 0o600
12
13
 
13
14
  module_function
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ require 'json'
7
+ require 'fileutils'
8
+
9
+ module RosettAi
10
+ module SessionHooks
11
+ # Idempotently wires a Ruby script into the Claude Code settings.json
12
+ # SessionStart and PostToolUse hook sections.
13
+ #
14
+ # The installer reads the settings file, appends a new hook block if the
15
+ # target command is not already present, and atomically writes the result.
16
+ # A second install call is a no-op.
17
+ #
18
+ # @example
19
+ # installer = RosettAi::SessionHooks::Installer.new(
20
+ # script_path: '/path/to/write_heartbeat.rb'
21
+ # )
22
+ # result = installer.install
23
+ # result[:modified_types] #=> ["SessionStart", "PostToolUse"]
24
+ #
25
+ # @author hugo
26
+ # @author claude
27
+ class Installer
28
+ # Default path to the global Claude Code settings file.
29
+ SETTINGS_PATH = File.expand_path('~/.claude/settings.json').freeze
30
+
31
+ # Hook event types that receive the heartbeat hook.
32
+ HOOK_TYPES = ['SessionStart', 'PostToolUse'].freeze
33
+
34
+ # @param script_path [String] absolute path to the Ruby hook script
35
+ # @param timeout [Integer] hook timeout in seconds
36
+ # @param settings_path [String] path to settings.json (injectable for tests)
37
+ def initialize(script_path:, timeout: 5, settings_path: SETTINGS_PATH)
38
+ @script_path = script_path.to_s
39
+ @timeout = Integer(timeout)
40
+ @settings_path = settings_path.to_s
41
+ end
42
+
43
+ # Install the hook into SessionStart and PostToolUse if not already present.
44
+ #
45
+ # @return [Hash] result with keys :modified_types and :already_present_types
46
+ # @raise [RosettAi::SessionHooksError] if settings file cannot be read or written
47
+ def install
48
+ settings = load_settings
49
+ modified, already_present = classify_hooks(settings)
50
+ write_settings(settings) unless modified.empty?
51
+ { modified_types: modified, already_present_types: already_present }
52
+ end
53
+
54
+ # Check whether the hook is present in all required event types.
55
+ #
56
+ # @return [Boolean]
57
+ def installed?
58
+ settings = load_settings
59
+ HOOK_TYPES.all? { |ht| hook_present?(settings, ht) }
60
+ end
61
+
62
+ private
63
+
64
+ # @return [Array<Array>] [modified_types, already_present_types]
65
+ def classify_hooks(settings)
66
+ modified = []
67
+ already_present = []
68
+ HOOK_TYPES.each do |hook_type|
69
+ if hook_present?(settings, hook_type)
70
+ already_present << hook_type
71
+ else
72
+ inject_hook(settings, hook_type)
73
+ modified << hook_type
74
+ end
75
+ end
76
+ [modified, already_present]
77
+ end
78
+
79
+ # @return [Hash] parsed settings.json; empty hash if file absent
80
+ def load_settings
81
+ return {} unless File.exist?(@settings_path)
82
+
83
+ JSON.parse(File.read(@settings_path))
84
+ rescue JSON::ParserError => e
85
+ raise RosettAi::SessionHooksError, "Failed to parse #{@settings_path}: #{e.message}"
86
+ rescue SystemCallError => e
87
+ raise RosettAi::SessionHooksError, "Failed to read #{@settings_path}: #{e.message}"
88
+ end
89
+
90
+ # Atomically persist modified settings via tmp → rename.
91
+ def write_settings(settings)
92
+ content = JSON.pretty_generate(settings)
93
+ tmp = "#{@settings_path}.tmp"
94
+ FileUtils.mkdir_p(File.dirname(@settings_path))
95
+ File.write(tmp, content)
96
+ File.rename(tmp, @settings_path)
97
+ rescue SystemCallError => e
98
+ raise RosettAi::SessionHooksError, "Failed to write #{@settings_path}: #{e.message}"
99
+ end
100
+
101
+ # The hook entry object for the command.
102
+ def hook_entry
103
+ { 'type' => 'command', 'command' => command_string, 'timeout' => @timeout }
104
+ end
105
+
106
+ # The shell command string identifying this hook in settings.
107
+ def command_string
108
+ "ruby #{@script_path}"
109
+ end
110
+
111
+ # Returns true if any existing hook block in hook_type already has this command.
112
+ def hook_present?(settings, hook_type)
113
+ blocks = settings.dig('hooks', hook_type) || []
114
+ blocks.any? { |block| block_has_command?(block) }
115
+ end
116
+
117
+ # Returns true if the given hook block contains the target command.
118
+ def block_has_command?(block)
119
+ (block['hooks'] || []).any? { |h| h['command'] == command_string }
120
+ end
121
+
122
+ # Appends a new hook block containing the hook entry to the given event type.
123
+ def inject_hook(settings, hook_type)
124
+ hooks = settings['hooks'] ||= {}
125
+ hooks[hook_type] ||= []
126
+ hooks[hook_type] << { 'hooks' => [hook_entry] }
127
+ end
128
+ end
129
+ end
130
+ end
@@ -4,6 +4,7 @@
4
4
  # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
5
 
6
6
  module RosettAi
7
+ # Intelligent CLI command and flag suggestions.
7
8
  module SmartFeedback
8
9
  # Provides "Did you mean?" suggestions using Levenshtein distance.
9
10
  #
@@ -14,8 +15,11 @@ module RosettAi
14
15
  # @author hugo
15
16
  # @author claude
16
17
  class Suggester
18
+ # @return [Integer] Maximum number of feedback suggestions to show.
17
19
  MAX_SUGGESTIONS = 3
20
+ # @return [Integer] Minimum similarity score for command suggestions.
18
21
  COMMAND_THRESHOLD = 2
22
+ # @return [Integer] Minimum similarity score for flag suggestions.
19
23
  FLAG_THRESHOLD = 3
20
24
 
21
25
  # Find suggestion matches for a given input.
@@ -23,6 +23,13 @@ module RosettAi
23
23
 
24
24
  # Prepended module that wraps Thor command dispatch with smart feedback.
25
25
  module CommandDispatch
26
+ # Dispatch a Thor command with smart feedback middleware.
27
+ #
28
+ # @param meth [Object] the meth
29
+ # @param given_args [Object] the given args
30
+ # @param given_opts [Object] the given opts
31
+ # @param config [Object] the config
32
+ # @return [Object]
26
33
  def dispatch(meth, given_args, given_opts, config)
27
34
  super
28
35
  rescue ::Thor::UndefinedCommandError => e
@@ -27,6 +27,7 @@ module RosettAi
27
27
  # @author hugo
28
28
  # @author claude
29
29
  class StructuredLogger < ::Logger
30
+ # @return [Array] Supported structured log output formats.
30
31
  VALID_FORMATS = ['text', 'json'].freeze
31
32
 
32
33
  # @return [String] correlation ID for the current invocation (UUID v4)
@@ -14,6 +14,7 @@ module RosettAi
14
14
  # @author claude
15
15
  class LogRotator
16
16
  DEFAULT_MAX_SIZE = 10 * 1024 * 1024 # 10 MB
17
+ # @return [Integer] Default maximum number of log files to retain.
17
18
  DEFAULT_MAX_FILES = 5
18
19
 
19
20
  # @return [String] path to the log file
@@ -13,6 +13,7 @@ module RosettAi
13
13
  # @author claude
14
14
  # @see conf/design/monitoring_observability.yml
15
15
  module Telemetry
16
+ # @return [Array] Supported level values.
16
17
  LEVELS = ['debug', 'info', 'warn', 'error'].freeze
17
18
 
18
19
  # @return [Boolean] true if telemetry is enabled via environment variable
@@ -7,9 +7,11 @@ require 'thor'
7
7
  require 'rainbow'
8
8
 
9
9
  module RosettAi
10
+ # Thor CLI command framework and task definitions.
10
11
  module Thor
11
12
  # Main CLI entry point for Rosett-AI commands
12
13
  class CLI < ::Thor
14
+ # @return [Array] Thor commands excluded from user-facing help.
13
15
  INTERNAL_COMMANDS = ['build', 'release', 'documentation', 'dbus', 'desktop'].freeze
14
16
 
15
17
  def self.exit_on_failure?
@@ -89,6 +91,8 @@ module RosettAi
89
91
  end
90
92
 
91
93
  desc 'version', 'Display rosett-ai version'
94
+ # Return the version string.
95
+ # @return [String]
92
96
  def version
93
97
  puts ::I18n.t('rosett_ai.cli.version', version: RosettAi::VERSION)
94
98
  build_info = RosettAi.root.join('..', 'etc', 'BUILD_INFO')
@@ -146,6 +150,9 @@ module RosettAi
146
150
  desc 'config SUBCOMMAND', 'Compile and inspect AI tool configurations'
147
151
  subcommand 'config', RosettAi::Thor::Tasks::Config
148
152
 
153
+ desc 'backfill-user-yml', 'Backfill user.yml from ~/.claude/settings.json'
154
+ subcommand 'backfill-user-yml', RosettAi::Thor::Tasks::BackfillUserYml
155
+
149
156
  desc 'tooling SUBCOMMAND', 'Validate CI/CD files and check version consistency'
150
157
  subcommand 'tooling', RosettAi::Thor::Tasks::Tooling
151
158
 
@@ -195,6 +202,8 @@ module RosettAi
195
202
  subcommand 'plugins', RosettAi::Thor::Tasks::Plugins
196
203
 
197
204
  desc 'tree', 'Print a tree of all available commands'
205
+ # Display the CLI command tree.
206
+ # @return [void]
198
207
  def tree
199
208
  say 'rai', :blue
200
209
  leaves, groups = tree_partition_entries(self.class)
@@ -56,6 +56,8 @@ module RosettAi
56
56
  default: false,
57
57
  desc: 'Run analysis across all available engines (requires --api)'
58
58
 
59
+ # Perform analysis on the given files.
60
+ # @return [Hash]
59
61
  def analyze
60
62
  adopter = build_adopter
61
63
  files = adopter.discover_managed_files
@@ -0,0 +1,207 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-License-Identifier: GPL-3.0-only
4
+ # Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
5
+
6
+ require 'thor'
7
+ require 'json'
8
+ require 'rainbow'
9
+
10
+ module RosettAi
11
+ module Thor
12
+ module Tasks
13
+ # Backfill user.yml from the live Claude Code settings.json.
14
+ #
15
+ # Reads ~/.claude/settings.json and merges any permission entries or env vars
16
+ # not yet covered by the engine's user.yml source file. Shows a summary and
17
+ # prompts for confirmation before writing — never auto-applies unless --yes is
18
+ # given. Idempotent: re-running when nothing is uncovered is a no-op.
19
+ class BackfillUserYml < ::Thor
20
+ default_task :backfill
21
+
22
+ SETTINGS_PATH = File.expand_path('~/.claude/settings.json')
23
+
24
+ desc 'backfill', 'Backfill user.yml from ~/.claude/settings.json'
25
+ long_desc <<~LONGDESC
26
+ Reads ~/.claude/settings.json and merges any entries not yet captured
27
+ in the engine's user.yml YAML source. Shows what would be added, then
28
+ prompts for confirmation before writing.
29
+
30
+ Flags:
31
+ --target PATH YAML file to update (auto-detected if omitted)
32
+ --yes Apply without confirmation prompt
33
+
34
+ EXAMPLES
35
+
36
+ raictl backfill-user-yml
37
+ raictl backfill-user-yml --target conf/config/user.yml
38
+ raictl backfill-user-yml --yes
39
+
40
+ Related commands: raictl config compile, raictl config show user
41
+ LONGDESC
42
+ method_option :target, type: :string, default: nil,
43
+ desc: 'YAML file to update (default: auto-detected engine user.yml)'
44
+ method_option :yes, type: :boolean, default: false,
45
+ desc: 'Apply without confirmation'
46
+
47
+ # Run the backfill.
48
+ # @return [void]
49
+ def backfill
50
+ target_path = resolve_target
51
+ raise ::Thor::Error, "settings.json not found at #{SETTINGS_PATH}" unless File.exist?(SETTINGS_PATH)
52
+
53
+ unless File.exist?(target_path)
54
+ raise ::Thor::Error,
55
+ "user.yml not found at #{target_path}. Specify --target or install the engine."
56
+ end
57
+
58
+ settings = JSON.parse(File.read(SETTINGS_PATH))
59
+ user_yml = YAML.safe_load_file(target_path)
60
+ compiled = extract_compiled_stub(user_yml)
61
+ uncovered = find_uncovered(compiled, settings)
62
+
63
+ if uncovered.empty?
64
+ puts Rainbow('Nothing to backfill — user.yml already covers all entries.').green
65
+ return
66
+ end
67
+
68
+ total = count_leaves(uncovered)
69
+ say "Target : #{target_path}"
70
+ say "Found #{total} entr#{total == 1 ? 'y' : 'ies'} not in user.yml:\n"
71
+ print_uncovered(uncovered)
72
+ say
73
+
74
+ unless options[:yes]
75
+ answer = ask("Apply #{total} entr#{total == 1 ? 'y' : 'ies'} to user.yml? [y/N]")
76
+ unless answer.strip.downcase == 'y'
77
+ say 'Aborted — no changes written.'
78
+ return
79
+ end
80
+ end
81
+
82
+ apply_uncovered!(user_yml, uncovered)
83
+ warn_unmapped(uncovered)
84
+ File.write(target_path, user_yml.to_yaml)
85
+ say Rainbow("Wrote #{target_path} (#{total} entr#{total == 1 ? 'y' : 'ies'} added).").green
86
+ say 'Run `raictl config compile --simulate --verbose` to preview compiled output.'
87
+ end
88
+
89
+ private
90
+
91
+ def resolve_target
92
+ return File.expand_path(options[:target]) if options[:target]
93
+
94
+ candidates = [
95
+ File.expand_path('../../rosett-ai-engine-claude/conf/config/user.yml',
96
+ RosettAi.root),
97
+ find_installed_engine_user_yml
98
+ ].compact
99
+ found = candidates.find { |p| File.exist?(p) }
100
+ return found if found
101
+
102
+ raise ::Thor::Error,
103
+ "Cannot auto-detect user.yml. Use --target PATH.\nTried:\n" \
104
+ "#{candidates.map { |p| " #{p}" }.join("\n")}"
105
+ end
106
+
107
+ def find_installed_engine_user_yml
108
+ require 'rubygems'
109
+ spec = Gem::Specification.find_by_name('rosett-ai-engine-claude')
110
+ File.join(spec.gem_dir, 'conf', 'config', 'user.yml')
111
+ rescue Gem::MissingSpecError
112
+ nil
113
+ end
114
+
115
+ # Build a minimal compiled-form stub from user.yml so we can diff at the
116
+ # same key-naming level as settings.json (camelCase for JSON keys).
117
+ def extract_compiled_stub(user_yml_data)
118
+ stub = {}
119
+ perms = user_yml_data['permissions']
120
+ if perms.is_a?(Hash)
121
+ stub['permissions'] = {}
122
+ ['allow', 'deny', 'ask'].each do |k|
123
+ stub['permissions'][k] = Array(perms[k]) if perms.key?(k)
124
+ end
125
+ if perms.key?('additional_directories')
126
+ stub['permissions']['additionalDirectories'] = Array(perms['additional_directories'])
127
+ end
128
+ end
129
+ env = user_yml_data['env']
130
+ stub['env'] = env.transform_values(&:to_s) if env.is_a?(Hash)
131
+ stub
132
+ end
133
+
134
+ def find_uncovered(source_data, existing_data)
135
+ existing_data.each_with_object({}) do |(key, existing_val), result|
136
+ if source_data.key?(key)
137
+ uncovered = uncovered_value(source_data[key], existing_val)
138
+ result[key] = uncovered if uncovered
139
+ else
140
+ result[key] = existing_val
141
+ end
142
+ end
143
+ end
144
+
145
+ def uncovered_value(source_val, existing_val)
146
+ if source_val.is_a?(Array) && existing_val.is_a?(Array)
147
+ extra = existing_val - source_val
148
+ extra unless extra.empty?
149
+ elsif source_val.is_a?(Hash) && existing_val.is_a?(Hash)
150
+ sub = find_uncovered(source_val, existing_val)
151
+ sub unless sub.empty?
152
+ end
153
+ end
154
+
155
+ def apply_uncovered!(user_yml_data, uncovered)
156
+ user_yml_data['permissions'] ||= {}
157
+ perms_uncovered = uncovered['permissions'] || {}
158
+ ['allow', 'deny', 'ask'].each do |k|
159
+ next unless perms_uncovered.key?(k)
160
+
161
+ user_yml_data['permissions'][k] =
162
+ Array(user_yml_data['permissions'][k]) + perms_uncovered[k]
163
+ end
164
+ if perms_uncovered.key?('additionalDirectories')
165
+ user_yml_data['permissions']['additional_directories'] =
166
+ Array(user_yml_data['permissions']['additional_directories']) +
167
+ perms_uncovered['additionalDirectories']
168
+ end
169
+ return unless uncovered.key?('env')
170
+
171
+ user_yml_data['env'] ||= {}
172
+ uncovered['env'].each { |k, v| user_yml_data['env'][k] = v }
173
+ end
174
+
175
+ def warn_unmapped(uncovered)
176
+ other = uncovered.except('permissions', 'env')
177
+ return if other.empty?
178
+
179
+ say Rainbow("\nWarning: the following keys have no direct YAML mapping and were skipped:").yellow
180
+ other.each { |k, v| say " #{k}: #{v.inspect}" }
181
+ say 'Add them manually if needed.'
182
+ end
183
+
184
+ def count_leaves(hash)
185
+ hash.sum do |_k, v|
186
+ case v
187
+ when Hash then count_leaves(v)
188
+ when Array then v.size
189
+ else 1
190
+ end
191
+ end
192
+ end
193
+
194
+ def print_uncovered(uncovered, prefix = '')
195
+ uncovered.each do |key, val|
196
+ path = prefix.empty? ? key.to_s : "#{prefix}.#{key}"
197
+ case val
198
+ when Hash then print_uncovered(val, path)
199
+ when Array then val.each { |e| say " + #{path}[]: #{e}" }
200
+ else say " + #{path}: #{val.inspect}"
201
+ end
202
+ end
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
@@ -67,6 +67,8 @@ module RosettAi
67
67
  default: nil,
68
68
  desc: 'Output file path (shorthand for --destination)'
69
69
 
70
+ # Create the resource.
71
+ # @return [void]
70
72
  def create
71
73
  validate_options!
72
74
  compressor = resolve_compressor
@@ -105,6 +107,10 @@ module RosettAi
105
107
  default: true,
106
108
  desc: 'Restore local scope entries'
107
109
 
110
+ # Restore configuration from a backup archive.
111
+ #
112
+ # @param archive_path [Object] the archive path
113
+ # @return [void]
108
114
  def restore(archive_path)
109
115
  validate_archive!(archive_path)
110
116
  entries = extract_entries(archive_path)
@@ -37,6 +37,10 @@ module RosettAi
37
37
  default: ENV.fetch('USER', 'unknown'),
38
38
  desc: 'Author of the behaviour file'
39
39
 
40
+ # Add a new entry.
41
+ #
42
+ # @param name [Object] the name
43
+ # @return [void]
40
44
  def add(name)
41
45
  name = RosettAi::TextSanitizer.normalize_nfc(name)
42
46
  return if behaviour_exists?(name)
@@ -278,6 +282,8 @@ module RosettAi
278
282
  enum: ['table', 'json', 'yaml'],
279
283
  desc: 'Output format'
280
284
 
285
+ # Display a summary overview of behaviours.
286
+ # @return [void]
281
287
  def display
282
288
  behaviours = load_all_behaviours
283
289
 
@@ -306,6 +312,8 @@ module RosettAi
306
312
 
307
313
  raictl behaviour list
308
314
  LONGDESC
315
+ # List available items.
316
+ # @return [void]
309
317
  def list
310
318
  files = behaviour_files
311
319
  if files.empty?
@@ -329,6 +337,10 @@ module RosettAi
329
337
  raictl behaviour show code_generation
330
338
  raictl behaviour show security_rules
331
339
  LONGDESC
340
+ # Display detailed information for the named item.
341
+ #
342
+ # @param name [Object] the name
343
+ # @return [void]
332
344
  def show(name)
333
345
  name = RosettAi::TextSanitizer.normalize_nfc(name)
334
346
  file_path = find_behaviour_file(name)