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,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-only
|
|
4
|
+
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
|
+
|
|
6
|
+
module RosettAi
|
|
7
|
+
# User interface adapters.
|
|
8
|
+
module Ui
|
|
9
|
+
# Accessible TUI adapter for screen-reader-friendly output.
|
|
10
|
+
#
|
|
11
|
+
# Produces linear, sequential text without box-drawing characters or
|
|
12
|
+
# ANSI escape sequences. Auto-selected when assistive technology is
|
|
13
|
+
# detected (ORCA_RUNNING, BRLTTY_TTY).
|
|
14
|
+
class AccessibleTui < Tui
|
|
15
|
+
def render(content)
|
|
16
|
+
$stdout.puts(RosettAi::TextSanitizer.strip_ansi(String(content)))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def display_table(headers, rows)
|
|
20
|
+
widths = compute_column_widths(headers, rows)
|
|
21
|
+
|
|
22
|
+
header_line = format_row(headers, widths)
|
|
23
|
+
separator = widths.map { |w| '-' * w }.join(' ')
|
|
24
|
+
|
|
25
|
+
$stdout.puts(header_line)
|
|
26
|
+
$stdout.puts(separator)
|
|
27
|
+
rows.each { |row| $stdout.puts(format_row(row, widths)) }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def show_spinner(message)
|
|
31
|
+
$stdout.puts("Processing: #{message}...")
|
|
32
|
+
result = yield
|
|
33
|
+
$stdout.puts('Done.')
|
|
34
|
+
result
|
|
35
|
+
rescue StandardError => e
|
|
36
|
+
$stdout.puts('Failed.')
|
|
37
|
+
raise e
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def announce(message, priority: :polite)
|
|
41
|
+
prefix = priority == :assertive ? '[ASSERTIVE]' : '[POLITE]'
|
|
42
|
+
warn("#{prefix} #{message}")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def compute_column_widths(headers, rows)
|
|
48
|
+
all_rows = [headers] + rows
|
|
49
|
+
(0...headers.size).map do |col|
|
|
50
|
+
all_rows.map { |row| String(row[col]).length }.max
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def format_row(row, widths)
|
|
55
|
+
row.each_with_index.map { |cell, idx| String(cell).ljust(widths[idx]) }.join(' ')
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
Registry.register(:accessible_tui, AccessibleTui)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-only
|
|
4
|
+
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
|
+
|
|
6
|
+
module RosettAi
|
|
7
|
+
module Ui
|
|
8
|
+
# Abstract interface for UI implementations.
|
|
9
|
+
#
|
|
10
|
+
# All UI adapters (TUI, GTK4, Qt6) must inherit from this class and
|
|
11
|
+
# implement the required methods. The shared example
|
|
12
|
+
# 'a UI implementation' verifies conformance.
|
|
13
|
+
class Base
|
|
14
|
+
RTL_LOCALES = ['ar', 'he', 'fa', 'ur'].freeze
|
|
15
|
+
|
|
16
|
+
def render(content)
|
|
17
|
+
raise NotImplementedError, "#{self.class}#render not implemented"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def display_table(headers, rows)
|
|
21
|
+
raise NotImplementedError, "#{self.class}#display_table not implemented"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def prompt_user(question, choices: nil)
|
|
25
|
+
raise NotImplementedError, "#{self.class}#prompt_user not implemented"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def show_spinner(message, &)
|
|
29
|
+
raise NotImplementedError, "#{self.class}#show_spinner not implemented"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def announce(message)
|
|
33
|
+
raise NotImplementedError, "#{self.class}#announce not implemented"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def accessible?
|
|
37
|
+
ENV.key?('ORCA_RUNNING') || ENV.key?('BRLTTY_TTY')
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def text_direction(locale = nil)
|
|
41
|
+
lang = locale || ENV.fetch('LANG', 'en')[0, 2]
|
|
42
|
+
RTL_LOCALES.include?(lang) ? :rtl : :ltr
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-only
|
|
4
|
+
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
|
+
|
|
6
|
+
module RosettAi
|
|
7
|
+
# User interface adapters.
|
|
8
|
+
module Ui
|
|
9
|
+
# GTK4 adapter using ruby-gnome gtk4 gem.
|
|
10
|
+
#
|
|
11
|
+
# Implements all Base methods using native GTK4 widgets.
|
|
12
|
+
# Installed as part of the rosett-ai-gtk4 Debian package.
|
|
13
|
+
# Requires libgtk-4-dev and the gtk4 gem on the host system.
|
|
14
|
+
#
|
|
15
|
+
# Methods raise RosettAi::Error with install instructions if the gem
|
|
16
|
+
# is not available at runtime.
|
|
17
|
+
class Gtk4 < Base
|
|
18
|
+
UNAVAILABLE_MESSAGE = 'GTK4 adapter requires the gtk4 gem. Install: gem install gtk4'
|
|
19
|
+
|
|
20
|
+
def self.available?
|
|
21
|
+
require 'gtk4'
|
|
22
|
+
true
|
|
23
|
+
rescue LoadError
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def render(content)
|
|
28
|
+
require_gtk4!
|
|
29
|
+
text_view = ::Gtk::TextView.new
|
|
30
|
+
text_view.buffer.text = String(content)
|
|
31
|
+
text_view.editable = false
|
|
32
|
+
text_view
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def display_table(headers, rows)
|
|
36
|
+
require_gtk4!
|
|
37
|
+
store = build_list_store(headers.length)
|
|
38
|
+
populate_store(store, rows)
|
|
39
|
+
build_tree_view(store, headers)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def prompt_user(question, choices: nil) # rubocop:disable Lint/UnusedMethodArgument -- keyword name is part of public API
|
|
43
|
+
require_gtk4!
|
|
44
|
+
dialog = ::Gtk::MessageDialog.new(
|
|
45
|
+
message: question,
|
|
46
|
+
buttons: :ok_cancel
|
|
47
|
+
)
|
|
48
|
+
dialog.accessible_role = :dialog if dialog.respond_to?(:accessible_role=)
|
|
49
|
+
dialog
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def show_spinner(_message)
|
|
53
|
+
require_gtk4!
|
|
54
|
+
spinner = ::Gtk::Spinner.new
|
|
55
|
+
spinner.start
|
|
56
|
+
result = yield
|
|
57
|
+
spinner.stop
|
|
58
|
+
result
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def announce(message, priority: :polite)
|
|
62
|
+
warn("[GTK4:#{priority}] #{message}")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def require_gtk4!
|
|
68
|
+
require 'gtk4'
|
|
69
|
+
rescue LoadError
|
|
70
|
+
raise RosettAi::Error, UNAVAILABLE_MESSAGE
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def build_list_store(column_count)
|
|
74
|
+
types = Array.new(column_count, String)
|
|
75
|
+
::Gtk::ListStore.new(*types)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def populate_store(store, rows)
|
|
79
|
+
rows.each do |row|
|
|
80
|
+
iter = store.append
|
|
81
|
+
row.each_with_index { |cell, idx| iter[idx] = String(cell) }
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def build_tree_view(store, headers)
|
|
86
|
+
view = ::Gtk::TreeView.new(store)
|
|
87
|
+
headers.each_with_index do |header, idx|
|
|
88
|
+
renderer = ::Gtk::CellRendererText.new
|
|
89
|
+
column = ::Gtk::TreeViewColumn.new(header, renderer, text: idx)
|
|
90
|
+
view.append_column(column)
|
|
91
|
+
end
|
|
92
|
+
view
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
Registry.register(:gtk4, Gtk4)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-only
|
|
4
|
+
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
|
+
|
|
6
|
+
module RosettAi
|
|
7
|
+
# User interface adapters.
|
|
8
|
+
module Ui
|
|
9
|
+
# KDE skeleton adapter.
|
|
10
|
+
#
|
|
11
|
+
# Registers as :kde in the UI registry but raises on any method call.
|
|
12
|
+
# KDE integration requires Qt6 bindings which do not exist for Ruby.
|
|
13
|
+
# This adapter serves as a placeholder for the rosett-ai-kde package concept.
|
|
14
|
+
class Kde < Base
|
|
15
|
+
UNAVAILABLE_MESSAGE = 'KDE adapter not available — Ruby Qt6/KDE bindings do not exist. Use GTK4 or TUI.'
|
|
16
|
+
|
|
17
|
+
def render(_content)
|
|
18
|
+
raise RosettAi::Error, UNAVAILABLE_MESSAGE
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def display_table(_headers, _rows)
|
|
22
|
+
raise RosettAi::Error, UNAVAILABLE_MESSAGE
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def prompt_user(_question, choices: nil) # rubocop:disable Lint/UnusedMethodArgument -- skeleton raises unconditionally
|
|
26
|
+
raise RosettAi::Error, UNAVAILABLE_MESSAGE
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def show_spinner(_message)
|
|
30
|
+
raise RosettAi::Error, UNAVAILABLE_MESSAGE
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def announce(_message)
|
|
34
|
+
raise RosettAi::Error, UNAVAILABLE_MESSAGE
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
Registry.register(:kde, Kde)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-only
|
|
4
|
+
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
|
+
|
|
6
|
+
module RosettAi
|
|
7
|
+
# User interface adapters.
|
|
8
|
+
module Ui
|
|
9
|
+
# Qt6 skeleton adapter.
|
|
10
|
+
#
|
|
11
|
+
# Registers as :qt6 in the UI registry but raises on any method call.
|
|
12
|
+
# Ruby Qt6 bindings do not exist (qtbindings is unmaintained, Qt4-only).
|
|
13
|
+
# This adapter serves as a placeholder for the rosett-ai-qt6 package concept.
|
|
14
|
+
class Qt6 < Base
|
|
15
|
+
UNAVAILABLE_MESSAGE = 'Qt6 adapter not available — Ruby Qt6 bindings do not exist. Use GTK4 or TUI.'
|
|
16
|
+
|
|
17
|
+
def render(_content)
|
|
18
|
+
raise RosettAi::Error, UNAVAILABLE_MESSAGE
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def display_table(_headers, _rows)
|
|
22
|
+
raise RosettAi::Error, UNAVAILABLE_MESSAGE
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def prompt_user(_question, choices: nil) # rubocop:disable Lint/UnusedMethodArgument -- keyword name is part of public API
|
|
26
|
+
raise RosettAi::Error, UNAVAILABLE_MESSAGE
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def show_spinner(_message)
|
|
30
|
+
raise RosettAi::Error, UNAVAILABLE_MESSAGE
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def announce(_message)
|
|
34
|
+
raise RosettAi::Error, UNAVAILABLE_MESSAGE
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
Registry.register(:qt6, Qt6)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-only
|
|
4
|
+
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
|
+
|
|
6
|
+
module RosettAi
|
|
7
|
+
module Ui
|
|
8
|
+
# Discovers and manages installed UI plugins.
|
|
9
|
+
#
|
|
10
|
+
# Plugins register themselves via RosettAi::Ui::Registry.register.
|
|
11
|
+
# The registry selects the appropriate adapter at runtime based
|
|
12
|
+
# on user preference or available plugins.
|
|
13
|
+
class Registry
|
|
14
|
+
@adapters = {}
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
def register(name, adapter_class)
|
|
18
|
+
@adapters[name.to_sym] = adapter_class
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def resolve(name = nil)
|
|
22
|
+
key = name&.to_sym || default_adapter
|
|
23
|
+
adapter_class = @adapters[key]
|
|
24
|
+
|
|
25
|
+
unless adapter_class
|
|
26
|
+
available = @adapters.keys.join(', ')
|
|
27
|
+
raise RosettAi::Error, "Unknown UI adapter '#{key}'. Available: #{available}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
adapter_class.new
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def available
|
|
34
|
+
@adapters.keys
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def registered?(name)
|
|
38
|
+
@adapters.key?(name.to_sym)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def reset!
|
|
42
|
+
@adapters = {}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def default_adapter
|
|
48
|
+
return :accessible_tui if @adapters.key?(:accessible_tui) && accessible_environment?
|
|
49
|
+
return :tui if @adapters.key?(:tui)
|
|
50
|
+
|
|
51
|
+
@adapters.keys.first || raise(RosettAi::Error, 'No UI adapters registered')
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def accessible_environment?
|
|
55
|
+
Base.new.accessible?
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-only
|
|
4
|
+
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
|
+
|
|
6
|
+
require 'rainbow'
|
|
7
|
+
|
|
8
|
+
module RosettAi
|
|
9
|
+
module Ui
|
|
10
|
+
# TTY detection and safe interactive helpers for CLI commands.
|
|
11
|
+
#
|
|
12
|
+
# Provides guards for interactive prompts and spinners that degrade
|
|
13
|
+
# gracefully when stdout/stdin are not terminals (e.g., piped or
|
|
14
|
+
# redirected). Commands should use these helpers instead of calling
|
|
15
|
+
# TTY::Prompt or TTY::Spinner directly.
|
|
16
|
+
module TtyHelper
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
# Whether stdout and stdin are both connected to a terminal.
|
|
20
|
+
# @return [Boolean]
|
|
21
|
+
def interactive?
|
|
22
|
+
$stdout.tty? && $stdin.tty?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Ask a yes/no confirmation question.
|
|
26
|
+
#
|
|
27
|
+
# Returns true immediately when +force+ is true. In non-interactive
|
|
28
|
+
# mode (piped stdin/stdout), raises a Thor::Error with a hint to
|
|
29
|
+
# use --force.
|
|
30
|
+
#
|
|
31
|
+
# @param question [String] the confirmation question
|
|
32
|
+
# @param force [Boolean] skip the prompt entirely
|
|
33
|
+
# @return [Boolean]
|
|
34
|
+
# @raise [Thor::Error] when non-interactive and not forced
|
|
35
|
+
def confirm?(question, force: false)
|
|
36
|
+
return true if force
|
|
37
|
+
|
|
38
|
+
require_interactive!('Use --force to skip confirmation.')
|
|
39
|
+
|
|
40
|
+
require 'tty-prompt'
|
|
41
|
+
TTY::Prompt.new.yes?(question)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Ask for free-text input.
|
|
45
|
+
#
|
|
46
|
+
# In non-interactive mode, raises a Thor::Error with a hint about
|
|
47
|
+
# the equivalent CLI option.
|
|
48
|
+
#
|
|
49
|
+
# @param question [String] the prompt text
|
|
50
|
+
# @param option_hint [String, nil] CLI option name (e.g. 'description')
|
|
51
|
+
# @return [String]
|
|
52
|
+
# @raise [Thor::Error] when non-interactive
|
|
53
|
+
def ask(question, option_hint: nil)
|
|
54
|
+
hint = option_hint ? "Use --#{option_hint} to provide the value." : nil
|
|
55
|
+
require_interactive!(hint)
|
|
56
|
+
|
|
57
|
+
require 'tty-prompt'
|
|
58
|
+
TTY::Prompt.new.ask(question, required: true)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Guard that raises if the terminal is not interactive.
|
|
62
|
+
#
|
|
63
|
+
# @param hint [String, nil] additional guidance for the user
|
|
64
|
+
# @raise [Thor::Error]
|
|
65
|
+
def require_interactive!(hint = nil)
|
|
66
|
+
return if interactive?
|
|
67
|
+
|
|
68
|
+
message = 'Interactive input required but terminal is not available.'
|
|
69
|
+
message = "#{message} #{hint}" if hint
|
|
70
|
+
raise ::Thor::Error, message
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
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 'rainbow'
|
|
7
|
+
require 'terminal-table'
|
|
8
|
+
require 'tty-prompt'
|
|
9
|
+
require 'tty-spinner'
|
|
10
|
+
|
|
11
|
+
module RosettAi
|
|
12
|
+
# User interface adapters.
|
|
13
|
+
module Ui
|
|
14
|
+
# Terminal UI adapter using TTY gems.
|
|
15
|
+
#
|
|
16
|
+
# Default adapter for headless and terminal environments.
|
|
17
|
+
class Tui < Base
|
|
18
|
+
def initialize
|
|
19
|
+
super
|
|
20
|
+
Rainbow.enabled = false if ENV.key?('NO_COLOR')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def render(content)
|
|
24
|
+
$stdout.puts(content)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def display_table(headers, rows)
|
|
28
|
+
table = ::Terminal::Table.new(headings: headers, rows: rows)
|
|
29
|
+
$stdout.puts(table)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def prompt_user(question, choices: nil)
|
|
33
|
+
prompt = TTY::Prompt.new
|
|
34
|
+
if choices
|
|
35
|
+
prompt.select(question, choices)
|
|
36
|
+
else
|
|
37
|
+
prompt.ask(question)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def show_spinner(message)
|
|
42
|
+
spinner = TTY::Spinner.new("[:spinner] #{message}", format: :dots)
|
|
43
|
+
spinner.auto_spin
|
|
44
|
+
result = yield
|
|
45
|
+
spinner.success(Rainbow(' done').green)
|
|
46
|
+
result
|
|
47
|
+
rescue StandardError => e
|
|
48
|
+
spinner.error(Rainbow(' failed').red)
|
|
49
|
+
raise e
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def announce(message)
|
|
53
|
+
warn(message)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
Registry.register(:tui, Tui)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-only
|
|
4
|
+
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
|
+
|
|
6
|
+
module RosettAi
|
|
7
|
+
module Validators
|
|
8
|
+
# Validates behaviour configuration files against the behaviour JSON Schema.
|
|
9
|
+
#
|
|
10
|
+
# Thin wrapper around SchemaValidator. The SCHEMA_PATH constant is preserved
|
|
11
|
+
# for backward compatibility with existing specs and code that references it.
|
|
12
|
+
class BehaviourValidator < SchemaValidator
|
|
13
|
+
SCHEMA_PATH = 'conf/schemas/behaviour_schema.json'
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
super(schema: 'behaviour_schema.json')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-only
|
|
4
|
+
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
|
+
|
|
6
|
+
module RosettAi
|
|
7
|
+
module Validators
|
|
8
|
+
# Validates design documents against the design JSON Schema.
|
|
9
|
+
class DesignValidator < SchemaValidator
|
|
10
|
+
SCHEMA_PATH = 'conf/schemas/design_schema.json'
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
super(schema: 'design_schema.json')
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
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 'yaml'
|
|
7
|
+
require 'json'
|
|
8
|
+
require 'json_schemer'
|
|
9
|
+
|
|
10
|
+
module RosettAi
|
|
11
|
+
module Validators
|
|
12
|
+
# Generic JSON Schema validator for YAML configuration files.
|
|
13
|
+
#
|
|
14
|
+
# Subclasses specify which schema to use by passing the schema filename
|
|
15
|
+
# to the constructor. The schema is loaded from conf/schemas/ relative to
|
|
16
|
+
# the project root.
|
|
17
|
+
#
|
|
18
|
+
# API: valid?(file_path), validate(file_path), errors
|
|
19
|
+
class SchemaValidator
|
|
20
|
+
attr_reader :errors
|
|
21
|
+
|
|
22
|
+
def initialize(schema:)
|
|
23
|
+
@schema_filename = schema
|
|
24
|
+
@errors = []
|
|
25
|
+
@schemer = JSONSchemer.schema(load_schema)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def valid?(file_path)
|
|
29
|
+
@errors = []
|
|
30
|
+
content = load_file(file_path)
|
|
31
|
+
return false unless content
|
|
32
|
+
|
|
33
|
+
validate_schema(content)
|
|
34
|
+
@errors.empty?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def validate(file_path)
|
|
38
|
+
valid?(file_path)
|
|
39
|
+
@errors
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def schema_path
|
|
45
|
+
RosettAi.root.join('conf', 'schemas', @schema_filename)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def load_schema
|
|
49
|
+
JSON.parse(schema_path.read)
|
|
50
|
+
rescue Errno::ENOENT
|
|
51
|
+
raise RosettAi::ConfigurationError,
|
|
52
|
+
"JSON schema not found: #{schema_path}. " \
|
|
53
|
+
"Ensure conf/schemas/#{@schema_filename} exists."
|
|
54
|
+
rescue JSON::ParserError => e
|
|
55
|
+
raise RosettAi::ConfigurationError,
|
|
56
|
+
"Invalid JSON in schema #{@schema_filename}: #{e.message}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def load_file(file_path)
|
|
60
|
+
RosettAi::YamlLoader.load_file(file_path)
|
|
61
|
+
rescue Errno::ENOENT
|
|
62
|
+
@errors << "File not found: #{file_path}"
|
|
63
|
+
nil
|
|
64
|
+
rescue Psych::SyntaxError => e
|
|
65
|
+
@errors << "YAML syntax error: #{e.message}"
|
|
66
|
+
nil
|
|
67
|
+
rescue RosettAi::ValidationError => e
|
|
68
|
+
@errors << e.message
|
|
69
|
+
nil
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def validate_schema(content)
|
|
73
|
+
@schemer.validate(content).each do |error|
|
|
74
|
+
@errors << format_error(error)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def format_error(error)
|
|
79
|
+
path = error['data_pointer'].empty? ? 'root' : error['data_pointer']
|
|
80
|
+
"#{path}: #{error['type']}"
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# SPDX-License-Identifier: GPL-3.0-only
|
|
4
|
+
# Copyright (C) 2026 Hugo Antonio Sepulveda Manriquez / NeatNerds
|
|
5
|
+
|
|
6
|
+
module RosettAi
|
|
7
|
+
module Validators
|
|
8
|
+
# Validates tooling configuration files against the tooling JSON Schema.
|
|
9
|
+
class ToolingValidator < SchemaValidator
|
|
10
|
+
SCHEMA_PATH = 'conf/schemas/tooling_schema.json'
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
super(schema: 'tooling_schema.json')
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|