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.
- checksums.yaml +7 -0
- data/.ai-provenance.yml +119 -0
- data/.debride_whitelist +186 -0
- data/.fasterer.yml +29 -0
- data/.mdl_style.rb +10 -0
- data/.mdlrc +3 -0
- data/.mutant.yml +49 -0
- data/.namespace-allowlist +42 -0
- data/.reek.yml +1040 -0
- data/.rosett-ai/config.yml +3 -0
- data/.rspec +5 -0
- data/.rubocop.yml +380 -0
- data/.ruby-version +1 -0
- data/.yamllint +51 -0
- data/.yardopts +12 -0
- data/AI-DISCLOSURE.md +48 -0
- data/CHANGELOG.md +519 -0
- data/CLAUDE.md +141 -0
- data/CONTRIBUTING.md +734 -0
- data/INSTALL.md +154 -0
- data/LICENSE +674 -0
- data/LICENSE.md +675 -0
- data/QUICKSTART.md +73 -0
- data/README.md +366 -0
- data/Rakefile +200 -0
- data/SECURITY.md +114 -0
- data/bin/rai +1 -0
- data/cliff.toml +52 -0
- data/conf/adopt_redactions.yml +8 -0
- data/conf/behaviour/.gitkeep +0 -0
- data/conf/compliance/cra_rules.yml +25 -0
- data/conf/compliance/license_rules.yml +20 -0
- data/conf/design/aaif_alignment.yml +181 -0
- data/conf/design/ab_testing.yml +172 -0
- data/conf/design/accessibility.yml +84 -0
- data/conf/design/ai_authorship.yml +210 -0
- data/conf/design/ai_provenance.yml +224 -0
- data/conf/design/ai_tool_configuration.yml +207 -0
- data/conf/design/architecture.yml +139 -0
- data/conf/design/autocompletion.yml +115 -0
- data/conf/design/backward_compatibility.yml +112 -0
- data/conf/design/behaviour_composition.yml +246 -0
- data/conf/design/build_rake_extraction.yml +57 -0
- data/conf/design/ci_pipeline.yml +100 -0
- data/conf/design/claude_code_configuration.yml +157 -0
- data/conf/design/compiler.yml +128 -0
- data/conf/design/comply.yml +153 -0
- data/conf/design/content_packs.yml +84 -0
- data/conf/design/desktop_integration.yml +289 -0
- data/conf/design/distribution.yml +216 -0
- data/conf/design/doctor.yml +184 -0
- data/conf/design/documentation.yml +152 -0
- data/conf/design/engine_architecture.yml +257 -0
- data/conf/design/error_handling.yml +103 -0
- data/conf/design/feature_flags.yml +142 -0
- data/conf/design/git_hooks.yml +165 -0
- data/conf/design/gui_plugins.yml +475 -0
- data/conf/design/i18n.yml +84 -0
- data/conf/design/integration_testing.yml +56 -0
- data/conf/design/licensing_system.yml +88 -0
- data/conf/design/lifecycle_management.yml +208 -0
- data/conf/design/mcp_integration.yml +207 -0
- data/conf/design/mcp_settings.yml +126 -0
- data/conf/design/migration.yml +56 -0
- data/conf/design/monitoring_observability.yml +194 -0
- data/conf/design/namespace_cleanup.yml +145 -0
- data/conf/design/plugin_test_segregation.yml +145 -0
- data/conf/design/policy_management.yml +229 -0
- data/conf/design/project_management.yml +183 -0
- data/conf/design/rai_mcp_asset_discovery.yml +164 -0
- data/conf/design/rai_mcp_server.yml +605 -0
- data/conf/design/release_management.yml +117 -0
- data/conf/design/retrofit.yml +199 -0
- data/conf/design/retrospective_analyzer.yml +79 -0
- data/conf/design/scope_hierarchy.yml +352 -0
- data/conf/design/security.yml +115 -0
- data/conf/design/session_retrospective.yml +85 -0
- data/conf/design/smart_ui_feedback.yml +89 -0
- data/conf/design/structured_logging.yml +148 -0
- data/conf/design/styles.yml +123 -0
- data/conf/design/test_peer_review.yml +89 -0
- data/conf/design/testing.yml +136 -0
- data/conf/design/threat_model.yml +108 -0
- data/conf/design/ui_framework.yml +111 -0
- data/conf/design/usage_optimization.yml +122 -0
- data/conf/design/version_management.yml +60 -0
- data/conf/design/workflow.yml +227 -0
- data/conf/mcp/server_defaults.yml +42 -0
- data/conf/mcp/trust.yml +21 -0
- data/conf/packaging/core.yml +12 -0
- data/conf/packaging/gtk4.yml +11 -0
- data/conf/packaging/qt6.yml +11 -0
- data/conf/policy/default_deny_list.yml +197 -0
- data/conf/review/cli-command-audit.yml +857 -0
- data/conf/review/design-docs.yml +1064 -0
- data/conf/review/design-questionnaire.yml +153 -0
- data/conf/review/questionnaire.yml +146 -0
- data/conf/review/rosett-ai-core.yml +2919 -0
- data/conf/schemas/ai_config_schema.json +73 -0
- data/conf/schemas/behaviour_schema.json +132 -0
- data/conf/schemas/compliance_rule_schema.json +63 -0
- data/conf/schemas/content_pack_manifest_schema.json +51 -0
- data/conf/schemas/design_schema.json +210 -0
- data/conf/schemas/engine_manifest_schema.json +144 -0
- data/conf/schemas/lockfile_schema.json +74 -0
- data/conf/schemas/mcp_server_schema.json +48 -0
- data/conf/schemas/packaging_schema.json +70 -0
- data/conf/schemas/policy_schema.json +85 -0
- data/conf/schemas/provenance_schema.json +84 -0
- data/conf/schemas/rai_config_schema.json +56 -0
- data/conf/schemas/rai_project_schema.json +20 -0
- data/conf/schemas/scope_hierarchy_schema.json +49 -0
- data/conf/schemas/target_schema.json +67 -0
- data/conf/schemas/tooling_schema.json +65 -0
- data/conf/schemas/workflow_schema.json +112 -0
- data/conf/targets/agents_md.yml +17 -0
- data/conf/targets/claude.yml +12 -0
- data/conf/tooling/tools.yml +58 -0
- data/dist/rosett-ai-mcp.service +48 -0
- data/dist/rosett-ai-mcp.yml.default +45 -0
- data/doc/AAIF_POSITIONING.md +58 -0
- data/doc/ADOPT.md +224 -0
- data/doc/AI_PROVENANCE.md +139 -0
- data/doc/ARCHITECTURE.md +920 -0
- data/doc/BEHAVIOUR.md +409 -0
- data/doc/BUILD.md +138 -0
- data/doc/CI_CD_RECIPES.md +171 -0
- data/doc/CLAUDE_SESSIONS_MOVED.md +16 -0
- data/doc/COMMAND_ANALYSIS.md +229 -0
- data/doc/CONFIGURATION.md +281 -0
- data/doc/DESIGN_AUDIT.md +235 -0
- data/doc/DESIGN_PEER_REVIEW.md +771 -0
- data/doc/DESKTOP.md +447 -0
- data/doc/ENGINES.md +567 -0
- data/doc/ENGINE_DEVELOPMENT_GUIDE.md +417 -0
- data/doc/FEATURE_AUDIT.md +218 -0
- data/doc/IMPLEMENTATION_PLAN.md +669 -0
- data/doc/INCIDENT_REPORT_2026-02-02.md +251 -0
- data/doc/MIGRATION_GUIDE.md +88 -0
- data/doc/PACKAGING.md +232 -0
- data/doc/PROJECT_DASHBOARD.md +153 -0
- data/doc/PULP_DEPLOYMENT.md +164 -0
- data/doc/QUALITY_FIX_SUMMARY.md +110 -0
- data/doc/QUICK_START.md +162 -0
- data/doc/REEK_CONFIGURATION.md +166 -0
- data/doc/REFERENCE.md +253 -0
- data/doc/REFERENCES.md +324 -0
- data/doc/SECURITY_REVIEW_CHECKLIST.md +72 -0
- data/doc/SESSION_2026-02-28_GTK4_HARDENING.md +359 -0
- data/doc/SETUP.md +202 -0
- data/doc/TEST_PEER_REVIEW.md +152 -0
- data/doc/THREAT_MODEL.md +230 -0
- data/doc/USAGE.md +545 -0
- data/doc/USER_MANUAL.md +585 -0
- data/doc/ai_test_review_checklist.md +110 -0
- data/doc/changes/2026-02-18-packaging-fpm.md +155 -0
- data/doc/changes/2026-02-19-testing-infrastructure.md +221 -0
- data/doc/changes/2026-02-20-security-implementation.md +281 -0
- data/doc/changes/2026-02-20-styles-implementation.md +220 -0
- data/doc/changes/2026-02-21-architecture-completion.md +95 -0
- data/doc/changes/2026-02-21-architecture-ui-layer.md +253 -0
- data/doc/changes/2026-02-21-cc-config-implementation.md +108 -0
- data/doc/changes/2026-02-21-ci-pipeline-implementation.md +214 -0
- data/doc/changes/2026-02-21-compiler-multi-target-pipeline.md +241 -0
- data/doc/changes/2026-02-21-config-design-show-commands.md +61 -0
- data/doc/changes/2026-02-21-design-implementation-overview.md +455 -0
- data/doc/changes/2026-02-21-lifecycle-management.md +196 -0
- data/doc/changes/2026-02-21-path-resolver.md +128 -0
- data/doc/changes/2026-02-24-ci-tmpdir-mutant-fetch.md +45 -0
- data/doc/changes/2026-03-01-ci-bundler-strategy.md +120 -0
- data/doc/changes/2026-03-20-security-hardening-phase2.md +163 -0
- data/doc/context/SESSION-HANDOFF.md +69 -0
- data/doc/context/ai-engine-usage-trends-2026.md +80 -0
- data/doc/context/plan-pluggable-engines.md +590 -0
- data/doc/decisions/001-flog-deferred.md +32 -0
- data/doc/decisions/002-path-resolution-strategy.md +158 -0
- data/doc/decisions/003-ui-adapter-selection.md +193 -0
- data/doc/decisions/004-design-document-validation.md +179 -0
- data/doc/decisions/005-package-splitting-strategy.md +200 -0
- data/doc/decisions/006-multi-engine-architecture.md +147 -0
- data/doc/decisions/007-engine-agnostic-pivot.md +219 -0
- data/doc/decisions/008-ci-bundler-strategy.md +129 -0
- data/doc/decisions/009-core-only-v1-release.md +60 -0
- data/doc/decisions/010-engine-debian-packaging.md +66 -0
- data/doc/decisions/011-context-aware-cli.md +71 -0
- data/doc/dependency_decisions.yml +247 -0
- data/doc/issues/001-wrapper-missing-environment-variables.md +197 -0
- data/doc/issues/002-embedded-ruby-wrong-prefix.md +217 -0
- data/doc/issues/003-smoke-test-false-positive.md +127 -0
- data/doc/issues/004-market-research-design-updates.md +109 -0
- data/doc/issues/005-compile-scope-coexistence.md +161 -0
- data/doc/locales/.gitkeep +0 -0
- data/doc/man/rai.1.ronn +505 -0
- data/doc/operations/packaging.md +133 -0
- data/doc/operations/rosett-ai-release.md +65 -0
- data/doc/reference/error-catalog.md +107 -0
- data/doc/reference/rosett-ai-technical-reference.pdf +0 -0
- data/doc/reference/src/Pictures/cover.jpg +0 -0
- data/doc/reference/src/Pictures/head1.jpg +0 -0
- data/doc/reference/src/Pictures/head2.jpg +0 -0
- data/doc/reference/src/Pictures/head3.jpg +0 -0
- data/doc/reference/src/Pictures/head4.jpg +0 -0
- data/doc/reference/src/Pictures/head5.jpg +0 -0
- data/doc/reference/src/Pictures/head6.jpg +0 -0
- data/doc/reference/src/Pictures/head7.jpg +0 -0
- data/doc/reference/src/Pictures/head8.jpg +0 -0
- data/doc/reference/src/StyleInd.ist +4 -0
- data/doc/reference/src/bibliography.bib +79 -0
- data/doc/reference/src/main.tex +1288 -0
- data/doc/reference/src/structure.tex +303 -0
- data/doc/rosett-ai-bookmarks.html +301 -0
- data/kitchen.yml +46 -0
- data/lib/rosett_ai/adopter/executor_resolver.rb +77 -0
- data/lib/rosett_ai/adopter/local_analysis_collector.rb +154 -0
- data/lib/rosett_ai/adopter/rule_adopter.rb +254 -0
- data/lib/rosett_ai/ai_config/config_compiler.rb +111 -0
- data/lib/rosett_ai/ai_config/context_window.rb +55 -0
- data/lib/rosett_ai/ai_config/cost_controls.rb +44 -0
- data/lib/rosett_ai/ai_config/fallback_chain.rb +64 -0
- data/lib/rosett_ai/ai_config/model_router.rb +121 -0
- data/lib/rosett_ai/ai_config/validator.rb +45 -0
- data/lib/rosett_ai/authorship/attribution_compiler.rb +99 -0
- data/lib/rosett_ai/authorship/disclosure_policy.rb +81 -0
- data/lib/rosett_ai/authorship/review_validator.rb +39 -0
- data/lib/rosett_ai/authorship/trailer_generator.rb +88 -0
- data/lib/rosett_ai/backup/compressor.rb +180 -0
- data/lib/rosett_ai/backup/destination.rb +91 -0
- data/lib/rosett_ai/behaviour/manager.rb +156 -0
- data/lib/rosett_ai/compiler/backend.rb +86 -0
- data/lib/rosett_ai/compiler/backends/agents_md_backend.rb +80 -0
- data/lib/rosett_ai/compiler/backends/claude_backend.rb +88 -0
- data/lib/rosett_ai/compiler/backends/generic_backend.rb +15 -0
- data/lib/rosett_ai/compiler/behaviour_compiler.rb +40 -0
- data/lib/rosett_ai/compiler/capability_checker.rb +104 -0
- data/lib/rosett_ai/compiler/compilation_pipeline.rb +361 -0
- data/lib/rosett_ai/compiler/compiled_output.rb +39 -0
- data/lib/rosett_ai/compiler/locale_compiler.rb +250 -0
- data/lib/rosett_ai/compiler/target_profile.rb +112 -0
- data/lib/rosett_ai/completion/generator.rb +101 -0
- data/lib/rosett_ai/completion/shells/bash_generator.rb +126 -0
- data/lib/rosett_ai/completion/shells/fish_generator.rb +78 -0
- data/lib/rosett_ai/completion/shells/zsh_generator.rb +126 -0
- data/lib/rosett_ai/comply/checkers/cra_checker.rb +102 -0
- data/lib/rosett_ai/comply/checkers/license_checker.rb +85 -0
- data/lib/rosett_ai/comply/checkers/spdx_header_checker.rb +98 -0
- data/lib/rosett_ai/comply/reporter.rb +113 -0
- data/lib/rosett_ai/comply/runner.rb +50 -0
- data/lib/rosett_ai/composition/circular_dependency_detector.rb +56 -0
- data/lib/rosett_ai/composition/composer.rb +158 -0
- data/lib/rosett_ai/composition/composition_result.rb +64 -0
- data/lib/rosett_ai/composition/conflict_detector.rb +53 -0
- data/lib/rosett_ai/composition/lockfile.rb +103 -0
- data/lib/rosett_ai/composition/merge_strategy.rb +131 -0
- data/lib/rosett_ai/composition/priority_sorter.rb +29 -0
- data/lib/rosett_ai/composition/scope_resolver.rb +55 -0
- data/lib/rosett_ai/config/compile_result.rb +37 -0
- data/lib/rosett_ai/config/compiler.rb +13 -0
- data/lib/rosett_ai/config/domain_transformer.rb +13 -0
- data/lib/rosett_ai/config/key_map.rb +13 -0
- data/lib/rosett_ai/config/masking_secret_resolver.rb +40 -0
- data/lib/rosett_ai/config/scope_router.rb +13 -0
- data/lib/rosett_ai/config/secret_resolver.rb +125 -0
- data/lib/rosett_ai/configuration.rb +119 -0
- data/lib/rosett_ai/content/content_client.rb +60 -0
- data/lib/rosett_ai/content/pack_installer.rb +117 -0
- data/lib/rosett_ai/content/pack_manifest.rb +50 -0
- data/lib/rosett_ai/content/pack_registry.rb +68 -0
- data/lib/rosett_ai/content_packs/manager.rb +50 -0
- data/lib/rosett_ai/dbus/compositor_detector.rb +77 -0
- data/lib/rosett_ai/dbus/focus_adapters/base.rb +59 -0
- data/lib/rosett_ai/dbus/focus_adapters/gnome_adapter.rb +172 -0
- data/lib/rosett_ai/dbus/focus_adapters/hyprland_adapter.rb +77 -0
- data/lib/rosett_ai/dbus/focus_adapters/i3_adapter.rb +65 -0
- data/lib/rosett_ai/dbus/focus_adapters/kwin_adapter.rb +103 -0
- data/lib/rosett_ai/dbus/focus_adapters/x11_adapter.rb +105 -0
- data/lib/rosett_ai/dbus/focus_monitor_interface.rb +103 -0
- data/lib/rosett_ai/dbus/manager_interface.rb +213 -0
- data/lib/rosett_ai/dbus/plugin_manager_interface.rb +169 -0
- data/lib/rosett_ai/dbus/rate_limiter.rb +89 -0
- data/lib/rosett_ai/dbus/service.rb +121 -0
- data/lib/rosett_ai/dbus/status_notifier_interface.rb +79 -0
- data/lib/rosett_ai/deprecation.rb +79 -0
- data/lib/rosett_ai/desktop/dbus_client.rb +259 -0
- data/lib/rosett_ai/desktop/gtk4_app.rb +371 -0
- data/lib/rosett_ai/desktop/gtk4_preferences.rb +331 -0
- data/lib/rosett_ai/desktop/gui_logger.rb +236 -0
- data/lib/rosett_ai/doctor/check.rb +92 -0
- data/lib/rosett_ai/doctor/checks/cache_health_check.rb +50 -0
- data/lib/rosett_ai/doctor/checks/dbus_availability_check.rb +39 -0
- data/lib/rosett_ai/doctor/checks/engine_detection_check.rb +46 -0
- data/lib/rosett_ai/doctor/checks/file_permission_check.rb +44 -0
- data/lib/rosett_ai/doctor/checks/gem_dependency_check.rb +55 -0
- data/lib/rosett_ai/doctor/checks/ruby_version_check.rb +50 -0
- data/lib/rosett_ai/doctor/checks/stale_config_nncc_check.rb +57 -0
- data/lib/rosett_ai/doctor/checks/stale_home_nncc_check.rb +59 -0
- data/lib/rosett_ai/doctor.rb +81 -0
- data/lib/rosett_ai/documentation/reference_compiler.rb +122 -0
- data/lib/rosett_ai/documentation/translator.rb +62 -0
- data/lib/rosett_ai/engines/base_config_compiler.rb +203 -0
- data/lib/rosett_ai/engines/detector.rb +63 -0
- data/lib/rosett_ai/engines/registry.rb +50 -0
- data/lib/rosett_ai/error_handler.rb +139 -0
- data/lib/rosett_ai/exit_codes.rb +76 -0
- data/lib/rosett_ai/feature_flags.rb +102 -0
- data/lib/rosett_ai/formatting.rb +33 -0
- data/lib/rosett_ai/gem_consistency_checker.rb +199 -0
- data/lib/rosett_ai/git_hooks/chain_detector.rb +86 -0
- data/lib/rosett_ai/git_hooks/installer.rb +175 -0
- data/lib/rosett_ai/git_hooks/script_generator.rb +125 -0
- data/lib/rosett_ai/gitlab/validators/supplementary_gitlab_ci_yaml_validator.rb +79 -0
- data/lib/rosett_ai/i18n/locale_resolver.rb +46 -0
- data/lib/rosett_ai/i18n/utf8_checker.rb +32 -0
- data/lib/rosett_ai/init/config_file_writer.rb +24 -0
- data/lib/rosett_ai/init/directory_builder.rb +38 -0
- data/lib/rosett_ai/init/file_copier.rb +95 -0
- data/lib/rosett_ai/init/global_initializer.rb +28 -0
- data/lib/rosett_ai/init/local_initializer.rb +27 -0
- data/lib/rosett_ai/init/mcp_registrar.rb +109 -0
- data/lib/rosett_ai/init/project_initializer.rb +38 -0
- data/lib/rosett_ai/licensing/license_key.rb +139 -0
- data/lib/rosett_ai/licensing/license_store.rb +64 -0
- data/lib/rosett_ai/licensing/license_validator.rb +60 -0
- data/lib/rosett_ai/licensing/tier.rb +42 -0
- data/lib/rosett_ai/mcp/admin/auditor.rb +88 -0
- data/lib/rosett_ai/mcp/admin/health_checker.rb +81 -0
- data/lib/rosett_ai/mcp/admin/registry.rb +100 -0
- data/lib/rosett_ai/mcp/admin/schema_validator.rb +63 -0
- data/lib/rosett_ai/mcp/enforcement/.gitkeep +0 -0
- data/lib/rosett_ai/mcp/enforcement/hook_generator.rb +197 -0
- data/lib/rosett_ai/mcp/enforcement/validator.rb +215 -0
- data/lib/rosett_ai/mcp/governance.rb +160 -0
- data/lib/rosett_ai/mcp/http_security_config.rb +158 -0
- data/lib/rosett_ai/mcp/instructions.rb +266 -0
- data/lib/rosett_ai/mcp/key_hasher.rb +66 -0
- data/lib/rosett_ai/mcp/keyfile.rb +221 -0
- data/lib/rosett_ai/mcp/middleware/authentication.rb +146 -0
- data/lib/rosett_ai/mcp/middleware/content_type.rb +56 -0
- data/lib/rosett_ai/mcp/middleware/cors.rb +83 -0
- data/lib/rosett_ai/mcp/middleware/origin_validation.rb +73 -0
- data/lib/rosett_ai/mcp/middleware/rate_limit.rb +106 -0
- data/lib/rosett_ai/mcp/middleware/request_size.rb +51 -0
- data/lib/rosett_ai/mcp/plugins.rb +143 -0
- data/lib/rosett_ai/mcp/prompts/compilation_prompt.rb +40 -0
- data/lib/rosett_ai/mcp/prompts/compliance_prompt.rb +41 -0
- data/lib/rosett_ai/mcp/prompts/diagnostics_prompt.rb +41 -0
- data/lib/rosett_ai/mcp/prompts/validation_prompt.rb +41 -0
- data/lib/rosett_ai/mcp/resources/behaviour_resource.rb +127 -0
- data/lib/rosett_ai/mcp/resources/config_resource.rb +72 -0
- data/lib/rosett_ai/mcp/resources/design_resource.rb +58 -0
- data/lib/rosett_ai/mcp/resources/hooks_resource.rb +74 -0
- data/lib/rosett_ai/mcp/resources/provenance_resource.rb +51 -0
- data/lib/rosett_ai/mcp/resources/rules_resource.rb +60 -0
- data/lib/rosett_ai/mcp/resources/schema_resource.rb +72 -0
- data/lib/rosett_ai/mcp/response_helper.rb +46 -0
- data/lib/rosett_ai/mcp/security_logger.rb +60 -0
- data/lib/rosett_ai/mcp/server.rb +212 -0
- data/lib/rosett_ai/mcp/settings/server_installer.rb +112 -0
- data/lib/rosett_ai/mcp/settings/trust_manager.rb +142 -0
- data/lib/rosett_ai/mcp/tools/adopt_tool.rb +70 -0
- data/lib/rosett_ai/mcp/tools/backup_tool.rb +64 -0
- data/lib/rosett_ai/mcp/tools/behaviour_display_tool.rb +72 -0
- data/lib/rosett_ai/mcp/tools/behaviour_list_tool.rb +56 -0
- data/lib/rosett_ai/mcp/tools/behaviour_manage_tool.rb +114 -0
- data/lib/rosett_ai/mcp/tools/behaviour_show_tool.rb +62 -0
- data/lib/rosett_ai/mcp/tools/compile_status_tool.rb +122 -0
- data/lib/rosett_ai/mcp/tools/compile_tool.rb +191 -0
- data/lib/rosett_ai/mcp/tools/comply_tool.rb +79 -0
- data/lib/rosett_ai/mcp/tools/config_compile_tool.rb +71 -0
- data/lib/rosett_ai/mcp/tools/config_status_tool.rb +79 -0
- data/lib/rosett_ai/mcp/tools/content_tool.rb +78 -0
- data/lib/rosett_ai/mcp/tools/context_query_tool.rb +156 -0
- data/lib/rosett_ai/mcp/tools/design_list_tool.rb +57 -0
- data/lib/rosett_ai/mcp/tools/design_show_tool.rb +69 -0
- data/lib/rosett_ai/mcp/tools/doctor_tool.rb +62 -0
- data/lib/rosett_ai/mcp/tools/documentation_status_tool.rb +45 -0
- data/lib/rosett_ai/mcp/tools/engines_tool.rb +84 -0
- data/lib/rosett_ai/mcp/tools/hook_install_tool.rb +190 -0
- data/lib/rosett_ai/mcp/tools/hook_preview_tool.rb +173 -0
- data/lib/rosett_ai/mcp/tools/hooks_status_tool.rb +84 -0
- data/lib/rosett_ai/mcp/tools/init_tool.rb +87 -0
- data/lib/rosett_ai/mcp/tools/license_status_tool.rb +44 -0
- data/lib/rosett_ai/mcp/tools/project_tool.rb +117 -0
- data/lib/rosett_ai/mcp/tools/provenance_tool.rb +97 -0
- data/lib/rosett_ai/mcp/tools/provenance_write_tool.rb +40 -0
- data/lib/rosett_ai/mcp/tools/retrofit_tool.rb +81 -0
- data/lib/rosett_ai/mcp/tools/rule_search_tool.rb +163 -0
- data/lib/rosett_ai/mcp/tools/schema_get_tool.rb +94 -0
- data/lib/rosett_ai/mcp/tools/tooling_tool.rb +86 -0
- data/lib/rosett_ai/mcp/tools/validate_tool.rb +105 -0
- data/lib/rosett_ai/mcp/tools/workflow_execute_tool.rb +74 -0
- data/lib/rosett_ai/mcp/tools/workflow_tool.rb +78 -0
- data/lib/rosett_ai/migration/detector.rb +117 -0
- data/lib/rosett_ai/migration/nncc_config_migrator.rb +94 -0
- data/lib/rosett_ai/migration/nncc_project_migrator.rb +90 -0
- data/lib/rosett_ai/migration/xdg_migrator.rb +123 -0
- data/lib/rosett_ai/package_manager/apt.rb +108 -0
- data/lib/rosett_ai/package_manager/base.rb +68 -0
- data/lib/rosett_ai/package_manager/gem_backend.rb +90 -0
- data/lib/rosett_ai/packaging/variant_config.rb +92 -0
- data/lib/rosett_ai/path_resolver.rb +115 -0
- data/lib/rosett_ai/plugins/contract.rb +43 -0
- data/lib/rosett_ai/plugins/engine_contract.rb +60 -0
- data/lib/rosett_ai/plugins/gui_contract.rb +74 -0
- data/lib/rosett_ai/plugins/mcp_contract.rb +48 -0
- data/lib/rosett_ai/plugins/registry.rb +150 -0
- data/lib/rosett_ai/policy/auditor.rb +41 -0
- data/lib/rosett_ai/policy/deny_list.rb +71 -0
- data/lib/rosett_ai/policy/opt_out_scanner.rb +37 -0
- data/lib/rosett_ai/policy/policy_compiler.rb +84 -0
- data/lib/rosett_ai/policy/protected_files.rb +47 -0
- data/lib/rosett_ai/policy/tier_hierarchy.rb +48 -0
- data/lib/rosett_ai/policy/validator.rb +35 -0
- data/lib/rosett_ai/profiler.rb +79 -0
- data/lib/rosett_ai/project/drift_detector.rb +126 -0
- data/lib/rosett_ai/project/manager.rb +115 -0
- data/lib/rosett_ai/project/sync_manager.rb +138 -0
- data/lib/rosett_ai/project/template_applier.rb +105 -0
- data/lib/rosett_ai/project_context.rb +82 -0
- data/lib/rosett_ai/provenance/entry.rb +63 -0
- data/lib/rosett_ai/provenance/file_source.rb +32 -0
- data/lib/rosett_ai/provenance/source.rb +62 -0
- data/lib/rosett_ai/provenance/store.rb +153 -0
- data/lib/rosett_ai/provenance/tracker.rb +62 -0
- data/lib/rosett_ai/provenance/trailer_generator.rb +43 -0
- data/lib/rosett_ai/provenance/validator.rb +45 -0
- data/lib/rosett_ai/quorum/collector.rb +59 -0
- data/lib/rosett_ai/quorum/comparator.rb +81 -0
- data/lib/rosett_ai/quorum/dispatcher.rb +57 -0
- data/lib/rosett_ai/quorum/strategies/adopt.rb +56 -0
- data/lib/rosett_ai/rai_config.rb +107 -0
- data/lib/rosett_ai/retrofit/base_parser.rb +66 -0
- data/lib/rosett_ai/retrofit/engine.rb +171 -0
- data/lib/rosett_ai/retrofit/parsers/agents_md_parser.rb +50 -0
- data/lib/rosett_ai/retrofit/parsers/claude_parser.rb +69 -0
- data/lib/rosett_ai/retrofit/parsers/cursor_parser.rb +82 -0
- data/lib/rosett_ai/retrofit/round_trip_validator.rb +65 -0
- data/lib/rosett_ai/retrofit/scanner.rb +47 -0
- data/lib/rosett_ai/retrofit/secret_detector.rb +87 -0
- data/lib/rosett_ai/secrets_resolver.rb +71 -0
- data/lib/rosett_ai/smart_feedback/suggester.rb +83 -0
- data/lib/rosett_ai/smart_feedback/thor_middleware.rb +84 -0
- data/lib/rosett_ai/structured_logger.rb +110 -0
- data/lib/rosett_ai/telemetry/json_lines_writer.rb +50 -0
- data/lib/rosett_ai/telemetry/log_rotator.rb +67 -0
- data/lib/rosett_ai/telemetry/provider.rb +26 -0
- data/lib/rosett_ai/telemetry/reporter.rb +144 -0
- data/lib/rosett_ai/telemetry.rb +47 -0
- data/lib/rosett_ai/text_sanitizer.rb +62 -0
- data/lib/rosett_ai/thor/cli.rb +269 -0
- data/lib/rosett_ai/thor/tasks/adopt.rb +250 -0
- data/lib/rosett_ai/thor/tasks/backup.rb +420 -0
- data/lib/rosett_ai/thor/tasks/behaviour.rb +474 -0
- data/lib/rosett_ai/thor/tasks/build.rb +1162 -0
- data/lib/rosett_ai/thor/tasks/compile.rb +415 -0
- data/lib/rosett_ai/thor/tasks/completion.rb +123 -0
- data/lib/rosett_ai/thor/tasks/comply.rb +82 -0
- data/lib/rosett_ai/thor/tasks/config.rb +265 -0
- data/lib/rosett_ai/thor/tasks/content.rb +193 -0
- data/lib/rosett_ai/thor/tasks/dbus.rb +321 -0
- data/lib/rosett_ai/thor/tasks/design.rb +258 -0
- data/lib/rosett_ai/thor/tasks/desktop.rb +129 -0
- data/lib/rosett_ai/thor/tasks/doctor.rb +127 -0
- data/lib/rosett_ai/thor/tasks/documentation.rb +321 -0
- data/lib/rosett_ai/thor/tasks/engines.rb +167 -0
- data/lib/rosett_ai/thor/tasks/hooks.rb +219 -0
- data/lib/rosett_ai/thor/tasks/init.rb +259 -0
- data/lib/rosett_ai/thor/tasks/license.rb +120 -0
- data/lib/rosett_ai/thor/tasks/mcp.rb +535 -0
- data/lib/rosett_ai/thor/tasks/migrate.rb +121 -0
- data/lib/rosett_ai/thor/tasks/plugins.rb +157 -0
- data/lib/rosett_ai/thor/tasks/project.rb +260 -0
- data/lib/rosett_ai/thor/tasks/provenance.rb +195 -0
- data/lib/rosett_ai/thor/tasks/release.rb +314 -0
- data/lib/rosett_ai/thor/tasks/retrofit.rb +90 -0
- data/lib/rosett_ai/thor/tasks/tooling.rb +308 -0
- data/lib/rosett_ai/thor/tasks/validate.rb +108 -0
- data/lib/rosett_ai/thor/tasks/workflow.rb +196 -0
- data/lib/rosett_ai/tooling/ci_yaml_validator.rb +37 -0
- data/lib/rosett_ai/tooling/version_checker.rb +35 -0
- data/lib/rosett_ai/ui/accessible_tui.rb +61 -0
- data/lib/rosett_ai/ui/base.rb +46 -0
- data/lib/rosett_ai/ui/gtk4.rb +98 -0
- data/lib/rosett_ai/ui/kde.rb +40 -0
- data/lib/rosett_ai/ui/qt6.rb +40 -0
- data/lib/rosett_ai/ui/registry.rb +60 -0
- data/lib/rosett_ai/ui/tty_helper.rb +74 -0
- data/lib/rosett_ai/ui/tui.rb +59 -0
- data/lib/rosett_ai/validators/behaviour_validator.rb +20 -0
- data/lib/rosett_ai/validators/design_validator.rb +17 -0
- data/lib/rosett_ai/validators/schema_validator.rb +84 -0
- data/lib/rosett_ai/validators/tooling_validator.rb +17 -0
- data/lib/rosett_ai/version.rb +8 -0
- data/lib/rosett_ai/version_consistency_checker.rb +129 -0
- data/lib/rosett_ai/workflow/audit_log.rb +86 -0
- data/lib/rosett_ai/workflow/engine.rb +142 -0
- data/lib/rosett_ai/workflow/manager.rb +82 -0
- data/lib/rosett_ai/workflow/schema_validator.rb +71 -0
- data/lib/rosett_ai/workflow/step_runner.rb +61 -0
- data/lib/rosett_ai/workflow/steps/prompt_step.rb +62 -0
- data/lib/rosett_ai/workflow/steps/rai_step.rb +74 -0
- data/lib/rosett_ai/workflow/steps/shell_step.rb +53 -0
- data/lib/rosett_ai/yaml_loader.rb +78 -0
- data/lib/rosett_ai.rb +221 -0
- data/lib/rubocop/cop/rosett_ai/shell_interpolation.rb +54 -0
- data/lib/rubocop/cop/rosett_ai/unsafe_const_get.rb +60 -0
- data/lib/rubocop/cop/rosett_ai/unsafe_send.rb +50 -0
- data/lib/rubocop/cop/rosett_ai/unsafe_yaml_load.rb +40 -0
- data/lib/rubocop/rosett_ai.rb +9 -0
- data/lib/scripts/generated/docker_hub_tags.rb +126 -0
- data/locales/.gitkeep +0 -0
- data/locales/ar.yml +579 -0
- data/locales/en.yml +571 -0
- data/locales/fr.yml +567 -0
- data/packaging/build-engine-deb.sh +81 -0
- data/packaging/scripts/postinst +17 -0
- data/packaging/scripts/postrm +19 -0
- data/packaging/scripts/prerm +10 -0
- data/packaging/wrapper.sh.template +38 -0
- data/rosett-ai.gemspec +63 -0
- data/rules/.gitkeep +0 -0
- data/scripts/publish/pulp_upload.sh +123 -0
- data/settings.json +29 -0
- data/share/applications/be.neatnerds.rosettai.desktop +29 -0
- data/share/dbus-1/interfaces/be.neatnerds.rosettai.xml +103 -0
- data/share/dbus-1/services/be.neatnerds.rosettai.service +3 -0
- data/share/templates/behaviour/criticalthinking.yml +69 -0
- metadata +810 -0
|
@@ -0,0 +1,127 @@
|
|
|
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 'terminal-table'
|
|
7
|
+
|
|
8
|
+
module RosettAi
|
|
9
|
+
module Thor
|
|
10
|
+
module Tasks
|
|
11
|
+
# CLI task for `rai doctor` — runtime diagnostics.
|
|
12
|
+
#
|
|
13
|
+
# @author hugo
|
|
14
|
+
# @author claude
|
|
15
|
+
class Doctor < ::Thor
|
|
16
|
+
default_task :status
|
|
17
|
+
|
|
18
|
+
desc 'status', 'Run all diagnostic checks'
|
|
19
|
+
long_desc <<~LONGDESC
|
|
20
|
+
Runs all registered diagnostic checks and displays a summary.
|
|
21
|
+
|
|
22
|
+
Checks include Ruby version, gem dependencies, file permissions,
|
|
23
|
+
D-Bus availability, engine detection, and cache health.
|
|
24
|
+
|
|
25
|
+
Exit codes: 0 = all pass, 1 = any warn, 2 = any fail.
|
|
26
|
+
|
|
27
|
+
EXAMPLES
|
|
28
|
+
|
|
29
|
+
raictl doctor
|
|
30
|
+
raictl doctor --check ruby_version
|
|
31
|
+
raictl doctor --format json
|
|
32
|
+
LONGDESC
|
|
33
|
+
method_option :check, type: :string, desc: 'Run only the named check'
|
|
34
|
+
method_option :format, type: :string, enum: ['table', 'json'], default: 'table',
|
|
35
|
+
desc: 'Output format'
|
|
36
|
+
def status
|
|
37
|
+
validate_check_name!(options[:check]) if options[:check]
|
|
38
|
+
results = RosettAi::Doctor.run_all(only: options[:check])
|
|
39
|
+
|
|
40
|
+
if options[:format] == 'json'
|
|
41
|
+
print_json(results)
|
|
42
|
+
else
|
|
43
|
+
print_header
|
|
44
|
+
print_table_output(results)
|
|
45
|
+
print_summary(results)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
code = RosettAi::Doctor.exit_code(results)
|
|
49
|
+
exit code unless code.zero?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def validate_check_name!(name)
|
|
55
|
+
return if RosettAi::Doctor.check_names.include?(name)
|
|
56
|
+
|
|
57
|
+
raise ::Thor::Error,
|
|
58
|
+
"Unknown check '#{name}'. Available: #{RosettAi::Doctor.check_names.join(', ')}"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def t(key, **args)
|
|
62
|
+
::I18n.t("rosett_ai.doctor.#{key}", **args)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def print_header
|
|
66
|
+
say "raictl #{RosettAi::VERSION} | Ruby #{RUBY_VERSION} | #{RUBY_PLATFORM}"
|
|
67
|
+
say ''
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def print_table_output(results)
|
|
71
|
+
table = ::Terminal::Table.new(
|
|
72
|
+
headings: [t('header.check'), t('header.status'), t('header.details')],
|
|
73
|
+
rows: results.map { |r| build_row(r) }
|
|
74
|
+
)
|
|
75
|
+
say table
|
|
76
|
+
say ''
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def build_row(result)
|
|
80
|
+
status_text = format_status(result[:status])
|
|
81
|
+
detail = result[:message]
|
|
82
|
+
detail = "#{detail}\n #{result[:remediation]}" if result[:remediation]
|
|
83
|
+
[result[:name], status_text, detail]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def format_status(status)
|
|
87
|
+
case status
|
|
88
|
+
when 'pass' then Rainbow('PASS').green
|
|
89
|
+
when 'warn' then Rainbow('WARN').yellow
|
|
90
|
+
when 'fail' then Rainbow('FAIL').red
|
|
91
|
+
else status.upcase
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def print_summary(results)
|
|
96
|
+
counts = results.group_by { |r| r[:status] }.transform_values(&:size)
|
|
97
|
+
total = results.size
|
|
98
|
+
warn_count = counts.fetch('warn', 0)
|
|
99
|
+
fail_count = counts.fetch('fail', 0)
|
|
100
|
+
|
|
101
|
+
if fail_count.positive?
|
|
102
|
+
say Rainbow(t('summary.failures', total: total, fail: fail_count)).red
|
|
103
|
+
elsif warn_count.positive?
|
|
104
|
+
say Rainbow(t('summary.warnings', total: total, warn: warn_count)).yellow
|
|
105
|
+
else
|
|
106
|
+
say Rainbow(t('summary.all_pass', total: total)).green
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def print_json(results)
|
|
111
|
+
output = {
|
|
112
|
+
rai_version: RosettAi::VERSION,
|
|
113
|
+
ruby_version: RUBY_VERSION,
|
|
114
|
+
platform: RUBY_PLATFORM,
|
|
115
|
+
checks: results,
|
|
116
|
+
summary: {
|
|
117
|
+
pass: results.count { |r| r[:status] == 'pass' },
|
|
118
|
+
warn: results.count { |r| r[:status] == 'warn' },
|
|
119
|
+
fail: results.count { |r| r[:status] == 'fail' }
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
say JSON.generate(output)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,321 @@
|
|
|
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 'tty-spinner'
|
|
8
|
+
require 'paint'
|
|
9
|
+
require 'pathname'
|
|
10
|
+
|
|
11
|
+
module RosettAi
|
|
12
|
+
module Thor
|
|
13
|
+
module Tasks
|
|
14
|
+
# Documentation management tasks
|
|
15
|
+
class Documentation < ::Thor
|
|
16
|
+
TYPE_COLORS = {
|
|
17
|
+
lib: :cyan, behaviour: :magenta, dependency: :yellow, reference: :blue
|
|
18
|
+
}.freeze
|
|
19
|
+
desc 'update', 'Update documentation based on code/config changes'
|
|
20
|
+
long_desc <<~LONGDESC
|
|
21
|
+
Scans the codebase for undocumented changes and updates documentation files accordingly.
|
|
22
|
+
Checks for new/changed methods, behaviour files, dependencies, and LaTeX reference documents.
|
|
23
|
+
|
|
24
|
+
Flags:
|
|
25
|
+
--locale: Target locale for documentation (default: en)
|
|
26
|
+
--all-locales: Update documentation for all configured locales
|
|
27
|
+
--dry-run: Show what would be updated without making changes
|
|
28
|
+
--skip-reference: Skip LaTeX reference document compilation
|
|
29
|
+
|
|
30
|
+
EXAMPLES
|
|
31
|
+
|
|
32
|
+
raictl documentation update
|
|
33
|
+
raictl documentation update --dry-run
|
|
34
|
+
raictl documentation update --all-locales
|
|
35
|
+
raictl documentation update --locale fr --skip-reference
|
|
36
|
+
|
|
37
|
+
Related commands: status, translate
|
|
38
|
+
LONGDESC
|
|
39
|
+
method_option :locale,
|
|
40
|
+
type: :string,
|
|
41
|
+
default: 'en',
|
|
42
|
+
desc: 'Target locale for documentation'
|
|
43
|
+
method_option :all_locales,
|
|
44
|
+
type: :boolean,
|
|
45
|
+
default: false,
|
|
46
|
+
desc: 'Update documentation for all configured locales'
|
|
47
|
+
method_option :dry_run,
|
|
48
|
+
type: :boolean,
|
|
49
|
+
default: false,
|
|
50
|
+
desc: 'Show what would be updated without making changes'
|
|
51
|
+
method_option :skip_reference,
|
|
52
|
+
type: :boolean,
|
|
53
|
+
default: false,
|
|
54
|
+
desc: 'Skip LaTeX reference document compilation'
|
|
55
|
+
|
|
56
|
+
def update
|
|
57
|
+
changes = scan_with_spinner
|
|
58
|
+
return puts Paint[t('no_updates'), :yellow] if changes.empty?
|
|
59
|
+
|
|
60
|
+
display_changes(changes)
|
|
61
|
+
return if options[:dry_run]
|
|
62
|
+
|
|
63
|
+
reference_changes, locale_changes = changes.partition { |change| change[:type] == :reference }
|
|
64
|
+
reference_changes.each { |_change| compile_reference_document! }
|
|
65
|
+
apply_changes_with_spinner(locale_changes) unless locale_changes.empty?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
desc 'status', 'Show documentation status and coverage'
|
|
69
|
+
long_desc <<~LONGDESC
|
|
70
|
+
Displays documentation file count, last modified timestamps, and configured locales.
|
|
71
|
+
Provides an overview of the current documentation state without making changes.
|
|
72
|
+
|
|
73
|
+
EXAMPLES
|
|
74
|
+
|
|
75
|
+
raictl documentation status
|
|
76
|
+
|
|
77
|
+
Related commands: update, translate
|
|
78
|
+
LONGDESC
|
|
79
|
+
def status
|
|
80
|
+
display_status_header
|
|
81
|
+
display_doc_files
|
|
82
|
+
display_configured_locales
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
desc 'translate', 'Translate documentation files'
|
|
86
|
+
long_desc <<~LONGDESC
|
|
87
|
+
Translates documentation files from one locale to another.
|
|
88
|
+
If no source file is specified, translates all markdown files in the doc/ directory.
|
|
89
|
+
|
|
90
|
+
Flags:
|
|
91
|
+
--from: Source locale (default: en)
|
|
92
|
+
--to: Target locale (required)
|
|
93
|
+
|
|
94
|
+
EXAMPLES
|
|
95
|
+
|
|
96
|
+
raictl documentation translate --to fr
|
|
97
|
+
raictl documentation translate doc/README.md --from en --to ar
|
|
98
|
+
|
|
99
|
+
Related commands: update, status
|
|
100
|
+
LONGDESC
|
|
101
|
+
method_option :from,
|
|
102
|
+
type: :string,
|
|
103
|
+
default: 'en',
|
|
104
|
+
desc: 'Source locale'
|
|
105
|
+
method_option :to,
|
|
106
|
+
type: :string,
|
|
107
|
+
required: true,
|
|
108
|
+
desc: 'Target locale'
|
|
109
|
+
|
|
110
|
+
def translate(source_file = nil)
|
|
111
|
+
files = source_file ? [source_file] : Dir.glob(RosettAi.root.join('doc', '*.md'))
|
|
112
|
+
|
|
113
|
+
translator = RosettAi::Documentation::Translator.new
|
|
114
|
+
|
|
115
|
+
files.each do |file|
|
|
116
|
+
unless File.exist?(file)
|
|
117
|
+
puts Rainbow(t('translate_source_missing', path: file)).red
|
|
118
|
+
next
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
result = translator.translate(file, from: options[:from], to: options[:to])
|
|
122
|
+
puts Rainbow(t('translate_done', path: result)).green
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
private
|
|
127
|
+
|
|
128
|
+
def t(key, **)
|
|
129
|
+
::I18n.t("rosett_ai.cli.documentation.#{key}", **)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def scan_with_spinner
|
|
133
|
+
spinner = TTY::Spinner.new('[:spinner] Scanning for changes...', format: :dots)
|
|
134
|
+
spinner.auto_spin
|
|
135
|
+
changes = scan_for_changes
|
|
136
|
+
spinner.success(Paint[t('scan_complete'), :green])
|
|
137
|
+
changes
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def apply_changes_with_spinner(changes)
|
|
141
|
+
spinner = TTY::Spinner.new("[:spinner] #{t('updating')}", format: :dots)
|
|
142
|
+
spinner.auto_spin
|
|
143
|
+
apply_changes(changes)
|
|
144
|
+
spinner.success(Paint[t('done'), :green])
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def display_status_header
|
|
148
|
+
puts Paint[t('status_title'), :bright]
|
|
149
|
+
puts '-' * 40
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def display_doc_files
|
|
153
|
+
doc_files = Dir.glob(RosettAi.root.join('doc', '*.md'))
|
|
154
|
+
puts t('doc_files', count: doc_files.count)
|
|
155
|
+
doc_files.each { |file| display_doc_file_info(file) }
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def display_doc_file_info(file)
|
|
159
|
+
basename = File.basename(file)
|
|
160
|
+
mtime = File.mtime(file).strftime('%Y-%m-%d %H:%M')
|
|
161
|
+
puts " #{Paint[basename, :cyan]}: #{mtime}"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def display_configured_locales
|
|
165
|
+
locale_dirs = Dir.glob(RosettAi.root.join('doc', 'locales', '*'))
|
|
166
|
+
puts "\n#{t('configured_locales', count: locale_dirs.count)}"
|
|
167
|
+
locale_dirs.each { |dir| puts " #{Paint[File.basename(dir), :cyan]}" }
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def scan_for_changes
|
|
171
|
+
changes = []
|
|
172
|
+
|
|
173
|
+
# Scan for new/changed configuration options in lib/
|
|
174
|
+
changes.concat(scan_lib_changes)
|
|
175
|
+
|
|
176
|
+
# Scan for new behaviour files
|
|
177
|
+
changes.concat(scan_behaviour_changes)
|
|
178
|
+
|
|
179
|
+
# Scan for dependency changes
|
|
180
|
+
changes.concat(scan_dependency_changes)
|
|
181
|
+
|
|
182
|
+
# Scan for stale LaTeX reference document
|
|
183
|
+
changes.concat(scan_reference_changes)
|
|
184
|
+
|
|
185
|
+
changes
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def scan_lib_changes
|
|
189
|
+
changes = []
|
|
190
|
+
lib_files = Dir.glob(RosettAi.root.join('lib', '**', '*.rb'))
|
|
191
|
+
|
|
192
|
+
lib_files.each do |file|
|
|
193
|
+
# Check for undocumented public methods
|
|
194
|
+
content = File.read(file)
|
|
195
|
+
if content.match?(/^\s*def\s+[^_]/) && !documented?(file)
|
|
196
|
+
changes << { type: :lib, file: file, reason: t('undocumented') }
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
changes
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def scan_behaviour_changes
|
|
204
|
+
changes = []
|
|
205
|
+
behaviour_files = Dir.glob(RosettAi.conf_root.join('conf', 'behaviour', '*.yml'))
|
|
206
|
+
doc_file = RosettAi.root.join('doc', 'BEHAVIOUR.md')
|
|
207
|
+
|
|
208
|
+
return changes unless doc_file.exist?
|
|
209
|
+
|
|
210
|
+
doc_content = doc_file.read
|
|
211
|
+
behaviour_files.each do |file|
|
|
212
|
+
basename = File.basename(file, '.yml')
|
|
213
|
+
unless doc_content.include?(basename)
|
|
214
|
+
changes << { type: :behaviour, file: file, reason: t('not_in_behaviour_md') }
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
changes
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def scan_dependency_changes
|
|
222
|
+
changes = []
|
|
223
|
+
gemfile = RosettAi.root.join('Gemfile')
|
|
224
|
+
doc_file = RosettAi.root.join('doc', 'SETUP.md')
|
|
225
|
+
|
|
226
|
+
return changes unless gemfile.exist? && doc_file.exist?
|
|
227
|
+
|
|
228
|
+
if gemfile.mtime > doc_file.mtime
|
|
229
|
+
changes << { type: :dependency, file: gemfile.to_s, reason: t('gemfile_newer') }
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
changes
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def scan_reference_changes
|
|
236
|
+
changes = []
|
|
237
|
+
return changes if options[:skip_reference]
|
|
238
|
+
|
|
239
|
+
compiler = RosettAi::Documentation::ReferenceCompiler.new
|
|
240
|
+
return changes unless compiler.source_dir.exist?
|
|
241
|
+
|
|
242
|
+
if !compiler.output_path.exist?
|
|
243
|
+
changes << { type: :reference, file: compiler.output_path.to_s,
|
|
244
|
+
reason: t('reference.missing') }
|
|
245
|
+
elsif compiler.stale?
|
|
246
|
+
changes << { type: :reference, file: compiler.output_path.to_s,
|
|
247
|
+
reason: t('reference.stale') }
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
changes
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def compile_reference_document!
|
|
254
|
+
compiler = RosettAi::Documentation::ReferenceCompiler.new
|
|
255
|
+
|
|
256
|
+
unless compiler.available?
|
|
257
|
+
puts Paint[t('reference.tools_missing', tools: compiler.missing_tools.join(', ')), :yellow]
|
|
258
|
+
return
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
spinner = TTY::Spinner.new("[:spinner] #{t('reference.compiling')}", format: :dots)
|
|
262
|
+
spinner.auto_spin
|
|
263
|
+
compiler.compile!
|
|
264
|
+
spinner.success(Paint[t('reference.compiled', path: compiler.output_path), :green])
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def documented?(file)
|
|
268
|
+
content = File.read(file)
|
|
269
|
+
# Simple heuristic: check for YARD-style documentation
|
|
270
|
+
content.match?(/^\s*#\s*@|^\s*# [A-Z]/)
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def display_changes(changes)
|
|
274
|
+
puts Paint["\n#{t('pending_updates')}", :bright]
|
|
275
|
+
changes.each do |change|
|
|
276
|
+
type_color = TYPE_COLORS[change[:type]]
|
|
277
|
+
puts " [#{Paint[change[:type].to_s.upcase, type_color]}] #{change[:file]}"
|
|
278
|
+
puts " Reason: #{change[:reason]}"
|
|
279
|
+
end
|
|
280
|
+
puts
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def apply_changes(changes)
|
|
284
|
+
target_locales.each do |locale|
|
|
285
|
+
changes.each { |change| apply_single_change(change, locale) }
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def target_locales
|
|
290
|
+
options[:all_locales] ? available_locales : [options[:locale]]
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def apply_single_change(change, locale)
|
|
294
|
+
case change[:type]
|
|
295
|
+
when :lib then update_api_documentation(change[:file], locale)
|
|
296
|
+
when :behaviour then update_behaviour_documentation(change[:file], locale)
|
|
297
|
+
when :dependency then update_setup_documentation(locale)
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def available_locales
|
|
302
|
+
locale_dirs = Dir.glob(RosettAi.root.join('doc', 'locales', '*'))
|
|
303
|
+
locales = locale_dirs.map { |dir| File.basename(dir) }
|
|
304
|
+
locales.empty? ? ['en'] : locales
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def update_api_documentation(file, locale)
|
|
308
|
+
puts " [not yet implemented] #{t('updating_api', file: File.basename(file), target_locale: locale)}"
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def update_behaviour_documentation(file, locale)
|
|
312
|
+
puts " [not yet implemented] #{t('updating_behaviour', file: File.basename(file), target_locale: locale)}"
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def update_setup_documentation(locale)
|
|
316
|
+
puts " [not yet implemented] #{t('updating_setup', target_locale: locale)}"
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
end
|
|
@@ -0,0 +1,167 @@
|
|
|
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 'terminal-table'
|
|
8
|
+
require 'rainbow'
|
|
9
|
+
|
|
10
|
+
module RosettAi
|
|
11
|
+
module Thor
|
|
12
|
+
module Tasks
|
|
13
|
+
# Thor task for engine detection and management
|
|
14
|
+
class Engines < ::Thor
|
|
15
|
+
desc 'list', 'List all known engines'
|
|
16
|
+
long_desc <<~LONGDESC
|
|
17
|
+
Lists all engines registered in the Rosett-AI ecosystem.
|
|
18
|
+
Displays engine name, display name, and version in a formatted table.
|
|
19
|
+
|
|
20
|
+
EXAMPLES
|
|
21
|
+
|
|
22
|
+
raictl engines list
|
|
23
|
+
|
|
24
|
+
Related commands: detect, status, plugins
|
|
25
|
+
LONGDESC
|
|
26
|
+
def list
|
|
27
|
+
rows = RosettAi::Engines::Registry.available.map do |name|
|
|
28
|
+
manifest = RosettAi::Engines::Registry.manifest(name)
|
|
29
|
+
[manifest['name'], manifest['display_name'], manifest['version']]
|
|
30
|
+
rescue StandardError => e
|
|
31
|
+
[name, Rainbow("error: #{e.message}").red, '?']
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
table = ::Terminal::Table.new(
|
|
35
|
+
title: Rainbow(t('list_title')).bright,
|
|
36
|
+
headings: [t('name'), t('display_name'), t('version')],
|
|
37
|
+
rows: rows,
|
|
38
|
+
style: { border: :unicode_round }
|
|
39
|
+
)
|
|
40
|
+
puts table
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
desc 'detect', 'Detect installed engines on this system'
|
|
44
|
+
long_desc <<~LONGDESC
|
|
45
|
+
Runs detection checks for all engines that have a detector component.
|
|
46
|
+
Shows which engines are installed and available on the current system.
|
|
47
|
+
|
|
48
|
+
EXAMPLES
|
|
49
|
+
|
|
50
|
+
raictl engines detect
|
|
51
|
+
|
|
52
|
+
Related commands: list, status, plugins
|
|
53
|
+
LONGDESC
|
|
54
|
+
def detect
|
|
55
|
+
rows = RosettAi::Engines::Registry.available.filter_map do |name|
|
|
56
|
+
manifest = RosettAi::Engines::Registry.manifest(name)
|
|
57
|
+
next unless manifest.dig('components', 'detector')
|
|
58
|
+
|
|
59
|
+
result = build_detector(name).detect
|
|
60
|
+
result[:checks].map do |check|
|
|
61
|
+
status = check[:passed] ? Rainbow(t('found')).green : Rainbow(t('not_found')).red
|
|
62
|
+
[result[:display_name], check[:type], check[:name], status]
|
|
63
|
+
end
|
|
64
|
+
rescue StandardError => e
|
|
65
|
+
[[name, 'manifest', '-', Rainbow("error: #{e.message}").red]]
|
|
66
|
+
end.flatten(1)
|
|
67
|
+
|
|
68
|
+
table = ::Terminal::Table.new(
|
|
69
|
+
title: Rainbow(t('detect_title')).bright,
|
|
70
|
+
headings: [t('engine'), t('check_type'), t('check_name'), t('status')],
|
|
71
|
+
rows: rows,
|
|
72
|
+
style: { border: :unicode_round }
|
|
73
|
+
)
|
|
74
|
+
puts table
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
desc 'status', 'Show default engine and detection status'
|
|
78
|
+
long_desc <<~LONGDESC
|
|
79
|
+
Displays the currently configured default engine and detection status for all engines.
|
|
80
|
+
Shows which engines are detected and which one is set as default.
|
|
81
|
+
|
|
82
|
+
EXAMPLES
|
|
83
|
+
|
|
84
|
+
raictl engines status
|
|
85
|
+
|
|
86
|
+
Related commands: list, detect, plugins
|
|
87
|
+
LONGDESC
|
|
88
|
+
def status
|
|
89
|
+
default_engine = RosettAi.rai_config.default_engine
|
|
90
|
+
puts "#{t('default_engine')}: #{Rainbow(default_engine).bright}"
|
|
91
|
+
puts
|
|
92
|
+
|
|
93
|
+
rows = RosettAi::Engines::Registry.available.map do |name|
|
|
94
|
+
manifest = RosettAi::Engines::Registry.manifest(name)
|
|
95
|
+
detected = if manifest.dig('components', 'detector')
|
|
96
|
+
result = build_detector(name).detect
|
|
97
|
+
result[:detected] ? Rainbow(t('yes')).green : Rainbow(t('no')).red
|
|
98
|
+
else
|
|
99
|
+
Rainbow(t('no_detector')).yellow
|
|
100
|
+
end
|
|
101
|
+
is_default = name == default_engine ? Rainbow(t('yes')).green : t('no')
|
|
102
|
+
[manifest['display_name'], detected, is_default]
|
|
103
|
+
rescue StandardError => e
|
|
104
|
+
[name, Rainbow("error: #{e.message}").red, '?']
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
table = ::Terminal::Table.new(
|
|
108
|
+
title: Rainbow(t('status_title')).bright,
|
|
109
|
+
headings: [t('engine'), t('detected'), t('default')],
|
|
110
|
+
rows: rows,
|
|
111
|
+
style: { border: :unicode_round }
|
|
112
|
+
)
|
|
113
|
+
puts table
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
desc 'plugins', 'Show registered plugin engines'
|
|
117
|
+
long_desc <<~LONGDESC
|
|
118
|
+
Lists all third-party plugin engines registered in the Rosett-AI plugin system.
|
|
119
|
+
Shows plugin name, display name, and version in a formatted table.
|
|
120
|
+
|
|
121
|
+
Related commands: list, detect, status
|
|
122
|
+
LONGDESC
|
|
123
|
+
def plugins
|
|
124
|
+
plugin_engines = RosettAi::Plugins::Registry.available(:engine)
|
|
125
|
+
|
|
126
|
+
if plugin_engines.empty?
|
|
127
|
+
puts Rainbow(t('no_plugins')).yellow
|
|
128
|
+
return
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
rows = plugin_engines.map do |name|
|
|
132
|
+
plugin = RosettAi::Plugins::Registry.plugin_module(:engine, name)
|
|
133
|
+
version = plugin.respond_to?(:version) ? plugin.version : '?'
|
|
134
|
+
display = plugin.respond_to?(:display_name) ? plugin.display_name : name
|
|
135
|
+
[name, display, version]
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
table = ::Terminal::Table.new(
|
|
139
|
+
title: Rainbow(t('plugins_title')).bright,
|
|
140
|
+
headings: [t('name'), t('display_name'), t('version')],
|
|
141
|
+
rows: rows,
|
|
142
|
+
style: { border: :unicode_round }
|
|
143
|
+
)
|
|
144
|
+
puts table
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
private
|
|
148
|
+
|
|
149
|
+
def t(key, **)
|
|
150
|
+
::I18n.t("rosett_ai.cli.engines.#{key}", **)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def build_detector(name)
|
|
154
|
+
manifest = RosettAi::Engines::Registry.manifest(name)
|
|
155
|
+
engine_mod = RosettAi::Engines::Registry.engine_module(name)
|
|
156
|
+
detector_klass = engine_mod.detector_class
|
|
157
|
+
|
|
158
|
+
if manifest.dig('components', 'detector') && detector_klass
|
|
159
|
+
detector_klass.new(name)
|
|
160
|
+
else
|
|
161
|
+
RosettAi::Engines::Detector.new(name)
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|