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,142 @@
|
|
|
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 Mcp
|
|
8
|
+
module Settings
|
|
9
|
+
# Manages trust sources for MCP server installation.
|
|
10
|
+
#
|
|
11
|
+
# Trust sources define which domains are approved for
|
|
12
|
+
# MCP server installation. Prevents untrusted servers
|
|
13
|
+
# from being silently added to configuration.
|
|
14
|
+
#
|
|
15
|
+
# @author hugo
|
|
16
|
+
# @author claude
|
|
17
|
+
class TrustManager
|
|
18
|
+
CONFIG_DIR = '.config/rosett-ai/mcp'
|
|
19
|
+
USER_TRUST_FILE = 'user_trust.yml'
|
|
20
|
+
|
|
21
|
+
# @param config_dir [Pathname, nil] override config directory
|
|
22
|
+
# @param defaults_path [Pathname, nil] override default trust sources file
|
|
23
|
+
def initialize(config_dir: nil, defaults_path: nil)
|
|
24
|
+
@config_dir = config_dir || Pathname.new(Dir.home).join(CONFIG_DIR)
|
|
25
|
+
@defaults_path = defaults_path || RosettAi.root.join('conf', 'mcp', 'trust.yml')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Lists all trusted sources (default + user-added).
|
|
29
|
+
#
|
|
30
|
+
# @return [Array<Hash>] trust source entries with :domain, :type, :description
|
|
31
|
+
def list
|
|
32
|
+
default_sources + user_sources
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Checks whether a domain is trusted.
|
|
36
|
+
#
|
|
37
|
+
# @param domain [String] domain to check
|
|
38
|
+
# @return [Boolean]
|
|
39
|
+
def trusted?(domain)
|
|
40
|
+
normalized = normalize_domain(domain)
|
|
41
|
+
list.any? { |source| normalize_domain(source[:domain]) == normalized }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Validates whether a URI originates from a trusted source.
|
|
45
|
+
#
|
|
46
|
+
# @param uri [String] URI to validate
|
|
47
|
+
# @return [Hash] result with :trusted, :domain, :source_type
|
|
48
|
+
def validate_uri(uri)
|
|
49
|
+
domain = extract_domain(uri)
|
|
50
|
+
source = find_source(domain)
|
|
51
|
+
|
|
52
|
+
if source
|
|
53
|
+
{ trusted: true, domain: domain, source_type: source[:type] }
|
|
54
|
+
else
|
|
55
|
+
{ trusted: false, domain: domain, source_type: nil }
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Adds a user-trusted domain.
|
|
60
|
+
#
|
|
61
|
+
# @param domain [String] domain to trust
|
|
62
|
+
# @param description [String] optional description
|
|
63
|
+
# @return [void]
|
|
64
|
+
def add_trust(domain, description: 'User-trusted domain')
|
|
65
|
+
sources = user_sources
|
|
66
|
+
normalized = normalize_domain(domain)
|
|
67
|
+
return if sources.any? { |s| normalize_domain(s[:domain]) == normalized }
|
|
68
|
+
|
|
69
|
+
sources << { domain: normalized, type: 'user', description: description }
|
|
70
|
+
write_user_sources(sources)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Removes a user-trusted domain.
|
|
74
|
+
#
|
|
75
|
+
# @param domain [String] domain to remove
|
|
76
|
+
# @return [Boolean] true if removed
|
|
77
|
+
def remove_trust(domain) # rubocop:disable Naming/PredicateMethod -- destructive action, not a predicate
|
|
78
|
+
sources = user_sources
|
|
79
|
+
normalized = normalize_domain(domain)
|
|
80
|
+
original_size = sources.size
|
|
81
|
+
sources.reject! { |s| normalize_domain(s[:domain]) == normalized }
|
|
82
|
+
|
|
83
|
+
return false if sources.size == original_size
|
|
84
|
+
|
|
85
|
+
write_user_sources(sources)
|
|
86
|
+
true
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
def default_sources
|
|
92
|
+
return [] unless @defaults_path.exist?
|
|
93
|
+
|
|
94
|
+
data = YAML.safe_load_file(@defaults_path, permitted_classes: [Symbol])
|
|
95
|
+
(data['trust_sources'] || []).map { |s| symbolize(s) }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def user_sources
|
|
99
|
+
path = user_trust_path
|
|
100
|
+
return [] unless path.exist?
|
|
101
|
+
|
|
102
|
+
data = YAML.safe_load_file(path, permitted_classes: [Symbol])
|
|
103
|
+
(data['trust_sources'] || []).map { |s| symbolize(s) }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def write_user_sources(sources)
|
|
107
|
+
FileUtils.mkdir_p(@config_dir)
|
|
108
|
+
data = { 'trust_sources' => sources.map { |s| stringify(s) } }
|
|
109
|
+
File.write(user_trust_path, YAML.dump(data))
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def user_trust_path
|
|
113
|
+
@config_dir.join(USER_TRUST_FILE)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def extract_domain(uri)
|
|
117
|
+
parsed = URI.parse(uri.to_s)
|
|
118
|
+
parsed.host || uri.to_s.split('/').first
|
|
119
|
+
rescue URI::InvalidURIError
|
|
120
|
+
uri.to_s.split('/').first
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def find_source(domain)
|
|
124
|
+
normalized = normalize_domain(domain)
|
|
125
|
+
list.find { |source| normalize_domain(source[:domain]) == normalized }
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def normalize_domain(domain)
|
|
129
|
+
domain.to_s.downcase.strip
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def symbolize(hash)
|
|
133
|
+
hash.transform_keys(&:to_sym)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def stringify(hash)
|
|
137
|
+
hash.transform_keys(&:to_s)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
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 Mcp
|
|
8
|
+
module Tools
|
|
9
|
+
# MCP tool: run rai adopt analysis.
|
|
10
|
+
#
|
|
11
|
+
# Performs local-only structural analysis of rai configuration.
|
|
12
|
+
# Read-only operation — does not modify any files.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class AdoptTool
|
|
17
|
+
TOOL_NAME = 'rai_adopt'
|
|
18
|
+
DESCRIPTION = 'Run rai adopt analysis (local structural checks)'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => true,
|
|
22
|
+
'destructiveHint' => false,
|
|
23
|
+
'idempotentHint' => true,
|
|
24
|
+
'openWorldHint' => false
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
INPUT_SCHEMA = {
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
elaborate: {
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
description: 'Show detailed findings (default: false)'
|
|
33
|
+
},
|
|
34
|
+
verbose: {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
description: 'Show processing details (default: false)'
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}.freeze
|
|
40
|
+
|
|
41
|
+
# Executes the adopt analysis.
|
|
42
|
+
#
|
|
43
|
+
# @param elaborate [Boolean] show detailed findings
|
|
44
|
+
# @param verbose [Boolean] show processing details
|
|
45
|
+
# @return [Hash] analysis results
|
|
46
|
+
def call(elaborate: false, verbose: false)
|
|
47
|
+
results = run_analysis
|
|
48
|
+
build_response(results['findings'] || [], elaborate: elaborate, verbose: verbose)
|
|
49
|
+
rescue StandardError => e
|
|
50
|
+
ResponseHelper.error("Adopt analysis failed: #{e.message}")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def build_response(issues, elaborate:, verbose:)
|
|
56
|
+
{ status: issues.empty? ? 'clean' : 'findings',
|
|
57
|
+
issues: elaborate ? issues : issues.first(5),
|
|
58
|
+
total_issues: issues.size, verbose: verbose, elaborate: elaborate }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def run_analysis
|
|
62
|
+
collector = RosettAi::Adopter::LocalAnalysisCollector.new
|
|
63
|
+
dir = RosettAi.root.join('conf', 'behaviour')
|
|
64
|
+
files = dir.directory? ? dir.glob('*.yml').map(&:to_s) : []
|
|
65
|
+
collector.analyze(files)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
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 Mcp
|
|
8
|
+
module Tools
|
|
9
|
+
# MCP tool: create rai backup.
|
|
10
|
+
#
|
|
11
|
+
# Backs up global and/or local rai configuration.
|
|
12
|
+
# Write operation — creates backup archive.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class BackupTool
|
|
17
|
+
TOOL_NAME = 'rai_backup'
|
|
18
|
+
DESCRIPTION = 'Create rai configuration backup'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => false,
|
|
22
|
+
'destructiveHint' => false,
|
|
23
|
+
'idempotentHint' => false,
|
|
24
|
+
'openWorldHint' => false
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
INPUT_SCHEMA = {
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
global: {
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
description: 'Back up global ~/.claude/ structure (default: false)'
|
|
33
|
+
},
|
|
34
|
+
local: {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
description: 'Back up project .claude/ and CLAUDE.md (default: false)'
|
|
37
|
+
},
|
|
38
|
+
compression: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
enum: ['zip', 'none'],
|
|
41
|
+
description: 'Compression format (default: zip)'
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}.freeze
|
|
45
|
+
|
|
46
|
+
# Executes the backup.
|
|
47
|
+
#
|
|
48
|
+
# @param global [Boolean] back up global structure
|
|
49
|
+
# @param local [Boolean] back up local structure
|
|
50
|
+
# @param compression [String] compression format
|
|
51
|
+
# @return [Hash] backup results
|
|
52
|
+
def call(global: false, local: false, compression: 'zip')
|
|
53
|
+
return ResponseHelper.error('At least one scope required: global or local') unless global || local
|
|
54
|
+
|
|
55
|
+
manager = RosettAi::Backup::Manager.new
|
|
56
|
+
result = manager.create(global: global, local: local, compression: compression)
|
|
57
|
+
ResponseHelper.success('Backup created', path: result[:path], size: result[:size])
|
|
58
|
+
rescue StandardError => e
|
|
59
|
+
ResponseHelper.error("Backup failed: #{e.message}")
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
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 Mcp
|
|
8
|
+
module Tools
|
|
9
|
+
# MCP tool: display behaviour configuration table.
|
|
10
|
+
#
|
|
11
|
+
# Returns a formatted overview of all behaviours with their
|
|
12
|
+
# rules, versions, and enabled status.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class BehaviourDisplayTool
|
|
17
|
+
TOOL_NAME = 'rai_behaviour_display'
|
|
18
|
+
DESCRIPTION = 'Display behaviour configuration overview'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => true,
|
|
22
|
+
'destructiveHint' => false,
|
|
23
|
+
'idempotentHint' => true,
|
|
24
|
+
'openWorldHint' => false
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
INPUT_SCHEMA = {
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
format: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
enum: ['json', 'table'],
|
|
33
|
+
description: 'Output format (default: json)'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}.freeze
|
|
37
|
+
|
|
38
|
+
# Executes the display operation.
|
|
39
|
+
#
|
|
40
|
+
# @param format [String] output format ('table' or 'json')
|
|
41
|
+
# @return [Hash] formatted behaviour display
|
|
42
|
+
def call(format: 'json')
|
|
43
|
+
dir = RosettAi.root.join('conf', 'behaviour')
|
|
44
|
+
return { behaviours: [], format: format } unless dir.directory?
|
|
45
|
+
|
|
46
|
+
behaviours = dir.glob('*.yml').filter_map { |path| load_display(path) }
|
|
47
|
+
{ behaviours: behaviours, format: format, total: behaviours.size }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def load_display(path)
|
|
53
|
+
data = YAML.safe_load_file(path, permitted_classes: [Symbol])
|
|
54
|
+
return nil unless data.is_a?(Hash)
|
|
55
|
+
|
|
56
|
+
rules = Array(data['rules'])
|
|
57
|
+
{
|
|
58
|
+
name: data['name'],
|
|
59
|
+
version: data['version'],
|
|
60
|
+
description: data['description'],
|
|
61
|
+
rules_count: rules.size,
|
|
62
|
+
enabled_rules: rules.count { |r| r['enabled'] != false },
|
|
63
|
+
sensitive: data['sensitive'] || false,
|
|
64
|
+
file: path.basename.to_s
|
|
65
|
+
}
|
|
66
|
+
rescue Psych::SyntaxError
|
|
67
|
+
nil
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
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 Mcp
|
|
8
|
+
module Tools
|
|
9
|
+
# MCP tool: list rai behaviour files.
|
|
10
|
+
#
|
|
11
|
+
# Returns a structured list of all behaviour files with
|
|
12
|
+
# metadata (name, version, rule count, enabled status).
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class BehaviourListTool
|
|
17
|
+
TOOL_NAME = 'rai_behaviour_list'
|
|
18
|
+
DESCRIPTION = 'List all rai behaviour configuration files'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => true,
|
|
22
|
+
'destructiveHint' => false,
|
|
23
|
+
'idempotentHint' => true,
|
|
24
|
+
'openWorldHint' => false
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
# Executes the listing.
|
|
28
|
+
#
|
|
29
|
+
# @return [Hash] result with :behaviours array
|
|
30
|
+
def call
|
|
31
|
+
dir = RosettAi.root.join('conf', 'behaviour')
|
|
32
|
+
return { behaviours: [] } unless dir.directory?
|
|
33
|
+
|
|
34
|
+
behaviours = dir.glob('*.yml').filter_map { |path| load_behaviour(path) }
|
|
35
|
+
{ behaviours: behaviours }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def load_behaviour(path)
|
|
41
|
+
data = YAML.safe_load_file(path, permitted_classes: [Symbol])
|
|
42
|
+
return nil unless data.is_a?(Hash)
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
name: data['name'],
|
|
46
|
+
version: data['version'],
|
|
47
|
+
rules: Array(data['rules']).size,
|
|
48
|
+
file: path.basename.to_s
|
|
49
|
+
}
|
|
50
|
+
rescue Psych::SyntaxError
|
|
51
|
+
nil
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
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 Mcp
|
|
8
|
+
module Tools
|
|
9
|
+
# MCP tool: manage behaviour files.
|
|
10
|
+
#
|
|
11
|
+
# Add, modify, or delete behaviour configurations.
|
|
12
|
+
# Write operation — destructive when action is 'delete'.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class BehaviourManageTool
|
|
17
|
+
TOOL_NAME = 'rai_behaviour_manage'
|
|
18
|
+
DESCRIPTION = 'Add, modify, or delete rai behaviour files'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => false,
|
|
22
|
+
'destructiveHint' => true,
|
|
23
|
+
'idempotentHint' => false,
|
|
24
|
+
'openWorldHint' => false
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
VALID_ACTIONS = ['add', 'modify', 'delete'].freeze
|
|
28
|
+
|
|
29
|
+
INPUT_SCHEMA = {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
action: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
enum: ['add', 'modify', 'delete'],
|
|
35
|
+
description: 'Management action to perform'
|
|
36
|
+
},
|
|
37
|
+
name: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
description: 'Behaviour name'
|
|
40
|
+
},
|
|
41
|
+
description: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
description: 'Behaviour description (for add/modify)'
|
|
44
|
+
},
|
|
45
|
+
force: {
|
|
46
|
+
type: 'boolean',
|
|
47
|
+
description: 'Skip confirmation for delete (default: false)'
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
required: ['action', 'name']
|
|
51
|
+
}.freeze
|
|
52
|
+
|
|
53
|
+
# Executes the behaviour management operation.
|
|
54
|
+
#
|
|
55
|
+
# @param action [String] one of 'add', 'modify', 'delete'
|
|
56
|
+
# @param name [String] behaviour name
|
|
57
|
+
# @param description [String, nil] behaviour description (for add/modify)
|
|
58
|
+
# @param force [Boolean] skip confirmation for delete
|
|
59
|
+
# @return [Hash] operation result
|
|
60
|
+
def call(action:, name:, description: nil, force: false)
|
|
61
|
+
return ResponseHelper.error("Invalid action: #{action}") unless VALID_ACTIONS.include?(action)
|
|
62
|
+
return ResponseHelper.error('Name is required') if name.nil? || name.empty?
|
|
63
|
+
|
|
64
|
+
case action
|
|
65
|
+
when 'add' then action_add(name, description: description)
|
|
66
|
+
when 'modify' then action_modify(name, description: description)
|
|
67
|
+
when 'delete' then action_delete(name, force: force)
|
|
68
|
+
end
|
|
69
|
+
rescue StandardError => e
|
|
70
|
+
ResponseHelper.error("Behaviour #{action} failed: #{e.message}")
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def action_add(name, description:, **)
|
|
76
|
+
manager = RosettAi::Behaviour::Manager.new
|
|
77
|
+
path = manager.add(name, description: description)
|
|
78
|
+
build_manage_response("Behaviour '#{name}' created", path)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def action_modify(name, description:, **)
|
|
82
|
+
manager = RosettAi::Behaviour::Manager.new
|
|
83
|
+
path = manager.modify(name, description: description)
|
|
84
|
+
build_manage_response("Behaviour '#{name}' modified", path)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def action_delete(name, force:, **)
|
|
88
|
+
manager = RosettAi::Behaviour::Manager.new
|
|
89
|
+
manager.delete(name, options: { force_delete: force })
|
|
90
|
+
ResponseHelper.success("Behaviour '#{name}' deleted")
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Builds a response that includes enforcement validation status.
|
|
94
|
+
#
|
|
95
|
+
# @param message [String]
|
|
96
|
+
# @param path [Pathname, nil]
|
|
97
|
+
# @return [Hash]
|
|
98
|
+
def build_manage_response(message, path)
|
|
99
|
+
response = ResponseHelper.success(message)
|
|
100
|
+
return response unless path.is_a?(Pathname) && path.exist?
|
|
101
|
+
|
|
102
|
+
data = RosettAi::YamlLoader.load_file(path.to_s)
|
|
103
|
+
enforcement = RosettAi::Mcp::Enforcement::Validator.new.validate(data)
|
|
104
|
+
response[:enforcement] = {
|
|
105
|
+
enforceable: enforcement[:valid].count { |r| r[:type] == 'enforceable' },
|
|
106
|
+
downgraded: enforcement[:downgraded].size,
|
|
107
|
+
warnings: enforcement[:downgraded].flat_map { |d| d[:warnings] }
|
|
108
|
+
}
|
|
109
|
+
response
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
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 Mcp
|
|
8
|
+
module Tools
|
|
9
|
+
# MCP tool: show a specific behaviour file.
|
|
10
|
+
#
|
|
11
|
+
# Returns the full content and metadata of a named behaviour.
|
|
12
|
+
# Read-only operation.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class BehaviourShowTool
|
|
17
|
+
TOOL_NAME = 'rai_behaviour_show'
|
|
18
|
+
DESCRIPTION = 'Show details of a specific rai behaviour'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => true,
|
|
22
|
+
'destructiveHint' => false,
|
|
23
|
+
'idempotentHint' => true,
|
|
24
|
+
'openWorldHint' => false
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
INPUT_SCHEMA = {
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
name: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
description: 'Behaviour name to display'
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
required: ['name']
|
|
36
|
+
}.freeze
|
|
37
|
+
|
|
38
|
+
# Executes the show operation.
|
|
39
|
+
#
|
|
40
|
+
# @param name [String] behaviour name (without .yml)
|
|
41
|
+
# @return [Hash] behaviour data or error
|
|
42
|
+
def call(name:)
|
|
43
|
+
path = RosettAi.root.join('conf', 'behaviour', "#{name}.yml")
|
|
44
|
+
return ResponseHelper.error("Behaviour not found: #{name}") unless path.exist?
|
|
45
|
+
|
|
46
|
+
data = YAML.safe_load_file(path, permitted_classes: [Symbol])
|
|
47
|
+
{
|
|
48
|
+
name: data['name'],
|
|
49
|
+
description: data['description'],
|
|
50
|
+
version: data['version'],
|
|
51
|
+
author: data['author'],
|
|
52
|
+
rules: Array(data['rules']),
|
|
53
|
+
sensitive: data['sensitive'] || false,
|
|
54
|
+
file: path.basename.to_s
|
|
55
|
+
}
|
|
56
|
+
rescue Psych::SyntaxError => e
|
|
57
|
+
ResponseHelper.error("YAML parse error in #{name}: #{e.message}")
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|