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,173 @@
|
|
|
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 'pathname'
|
|
8
|
+
|
|
9
|
+
module RosettAi
|
|
10
|
+
module Mcp
|
|
11
|
+
module Tools
|
|
12
|
+
# MCP tool: preview a generated enforcement hook script.
|
|
13
|
+
#
|
|
14
|
+
# Generates a Ruby hook script from behaviour rules without writing
|
|
15
|
+
# anything to disk. Allows inspection before installing via
|
|
16
|
+
# {HookInstallTool}. Strictly read-only.
|
|
17
|
+
#
|
|
18
|
+
# Delegates generation to {Enforcement::HookGenerator} and validation
|
|
19
|
+
# to {Enforcement::Validator}.
|
|
20
|
+
#
|
|
21
|
+
# @author hugo
|
|
22
|
+
# @author claude
|
|
23
|
+
class HookPreviewTool
|
|
24
|
+
TOOL_NAME = 'rai_hook_preview'
|
|
25
|
+
DESCRIPTION = 'Preview generated enforcement hook script (read-only, no side effects)'
|
|
26
|
+
|
|
27
|
+
ANNOTATIONS = {
|
|
28
|
+
'readOnlyHint' => true,
|
|
29
|
+
'destructiveHint' => false,
|
|
30
|
+
'idempotentHint' => true,
|
|
31
|
+
'openWorldHint' => false
|
|
32
|
+
}.freeze
|
|
33
|
+
|
|
34
|
+
INPUT_SCHEMA = {
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
behaviour_name: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
description: 'Behaviour to preview hook for (default: all enforceable)'
|
|
40
|
+
},
|
|
41
|
+
rule_id: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
description: 'Specific rule ID to preview hook for'
|
|
44
|
+
},
|
|
45
|
+
scope: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
description: 'Preview scope context'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}.freeze
|
|
51
|
+
|
|
52
|
+
# Generates a preview of the enforcement hook script.
|
|
53
|
+
#
|
|
54
|
+
# @param behaviour_name [String, nil] specific behaviour to generate for
|
|
55
|
+
# @param rule_id [String, nil] specific rule within the behaviour
|
|
56
|
+
# @param scope [String, nil] scope filter ('global', 'project')
|
|
57
|
+
# @return [Hash] generated script content and metadata
|
|
58
|
+
def call(behaviour_name: nil, rule_id: nil, scope: nil)
|
|
59
|
+
behaviours = load_behaviours(behaviour_name, scope)
|
|
60
|
+
validated = validate_and_collect(behaviours, rule_id)
|
|
61
|
+
|
|
62
|
+
return ResponseHelper.error('No enforceable rules found') if validated[:rules].empty?
|
|
63
|
+
|
|
64
|
+
script = generate_script(validated)
|
|
65
|
+
build_response(script, validated, scope)
|
|
66
|
+
rescue StandardError => e
|
|
67
|
+
ResponseHelper.error("Hook preview failed: #{e.message}")
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
# Loads behaviour files from the appropriate directories.
|
|
73
|
+
#
|
|
74
|
+
# @param behaviour_name [String, nil]
|
|
75
|
+
# @param scope [String, nil]
|
|
76
|
+
# @return [Array<Hash>] loaded behaviour data with metadata
|
|
77
|
+
def load_behaviours(behaviour_name, scope)
|
|
78
|
+
results = []
|
|
79
|
+
each_behaviour_file(scope) do |_path, data|
|
|
80
|
+
next if behaviour_name && data['name'] != behaviour_name
|
|
81
|
+
|
|
82
|
+
results << data
|
|
83
|
+
end
|
|
84
|
+
results
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Validates behaviours and collects enforceable rules.
|
|
88
|
+
#
|
|
89
|
+
# @param behaviours [Array<Hash>]
|
|
90
|
+
# @param rule_id [String, nil]
|
|
91
|
+
# @return [Hash] :rules, :downgraded, :behaviour_name, :behaviour_version
|
|
92
|
+
def validate_and_collect(behaviours, rule_id)
|
|
93
|
+
validator = Enforcement::Validator.new
|
|
94
|
+
all_rules = []
|
|
95
|
+
all_downgraded = []
|
|
96
|
+
names = []
|
|
97
|
+
|
|
98
|
+
behaviours.each do |data|
|
|
99
|
+
result = validator.validate(data)
|
|
100
|
+
rules = result[:valid].select { |r| r[:type] == 'enforceable' }
|
|
101
|
+
rules = rules.select { |r| r[:rule_id] == rule_id } if rule_id
|
|
102
|
+
all_rules.concat(rules)
|
|
103
|
+
all_downgraded.concat(result[:downgraded])
|
|
104
|
+
names << data['name']
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
{ rules: all_rules, downgraded: all_downgraded,
|
|
108
|
+
behaviour_name: names.join(', '),
|
|
109
|
+
behaviour_version: behaviours.first&.fetch('version', '0.0.0') || '0.0.0' }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Generates the hook script via HookGenerator.
|
|
113
|
+
#
|
|
114
|
+
# @param validated [Hash]
|
|
115
|
+
# @return [String]
|
|
116
|
+
def generate_script(validated)
|
|
117
|
+
generator = Enforcement::HookGenerator.new
|
|
118
|
+
generator.generate(
|
|
119
|
+
validated[:rules],
|
|
120
|
+
behaviour_name: validated[:behaviour_name],
|
|
121
|
+
behaviour_version: validated[:behaviour_version]
|
|
122
|
+
)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# @param script [String]
|
|
126
|
+
# @param validated [Hash]
|
|
127
|
+
# @param scope [String, nil]
|
|
128
|
+
# @return [Hash]
|
|
129
|
+
def build_response(script, validated, scope)
|
|
130
|
+
response = {
|
|
131
|
+
script: script,
|
|
132
|
+
rules_count: validated[:rules].size,
|
|
133
|
+
behaviours: validated[:rules].map { |r| r[:behaviour] }.uniq,
|
|
134
|
+
scope: scope || 'global',
|
|
135
|
+
preview_only: true
|
|
136
|
+
}
|
|
137
|
+
response[:downgraded] = validated[:downgraded] unless validated[:downgraded].empty?
|
|
138
|
+
response
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# @param scope [String, nil]
|
|
142
|
+
# @yield [Pathname, Hash]
|
|
143
|
+
def each_behaviour_file(scope)
|
|
144
|
+
dirs = behaviour_dirs(scope)
|
|
145
|
+
dirs.each do |dir|
|
|
146
|
+
next unless dir.directory?
|
|
147
|
+
|
|
148
|
+
dir.glob('*.yml').each do |path|
|
|
149
|
+
data = YAML.safe_load_file(path, permitted_classes: [Symbol])
|
|
150
|
+
yield path, data if data.is_a?(Hash)
|
|
151
|
+
rescue Psych::Exception
|
|
152
|
+
next
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# @param scope [String, nil]
|
|
158
|
+
# @return [Array<Pathname>]
|
|
159
|
+
def behaviour_dirs(scope)
|
|
160
|
+
case scope
|
|
161
|
+
when 'project'
|
|
162
|
+
[RosettAi.conf_root.join('conf', 'behaviour')]
|
|
163
|
+
else
|
|
164
|
+
dirs = [RosettAi.root.join('conf', 'behaviour')]
|
|
165
|
+
xdg = RosettAi.paths.rai_conf_dir.join('behaviour')
|
|
166
|
+
dirs << xdg if xdg.directory?
|
|
167
|
+
dirs
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
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
|
+
module RosettAi
|
|
7
|
+
module Mcp
|
|
8
|
+
module Tools
|
|
9
|
+
# MCP tool: show git hooks status.
|
|
10
|
+
#
|
|
11
|
+
# Lists configured hooks and their installation status.
|
|
12
|
+
# Read-only operation.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class HooksStatusTool
|
|
17
|
+
TOOL_NAME = 'rai_hooks_status'
|
|
18
|
+
DESCRIPTION = 'Show git hooks list and installation status'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => true,
|
|
22
|
+
'destructiveHint' => false,
|
|
23
|
+
'idempotentHint' => true,
|
|
24
|
+
'openWorldHint' => false
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
VALID_ACTIONS = ['list', 'status'].freeze
|
|
28
|
+
|
|
29
|
+
INPUT_SCHEMA = {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
action: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
enum: ['list', 'status'],
|
|
35
|
+
description: 'Hooks action (default: status)'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}.freeze
|
|
39
|
+
|
|
40
|
+
# Known overcommit hook phases.
|
|
41
|
+
HOOK_PHASES = [
|
|
42
|
+
'PreCommit', 'CommitMsg', 'PrePush', 'PreRebase',
|
|
43
|
+
'PostCheckout', 'PostCommit', 'PostMerge', 'PostRewrite'
|
|
44
|
+
].freeze
|
|
45
|
+
|
|
46
|
+
# Executes the hooks query.
|
|
47
|
+
#
|
|
48
|
+
# @param action [String] one of 'list' or 'status'
|
|
49
|
+
# @return [Hash] hooks information
|
|
50
|
+
def call(action: 'status')
|
|
51
|
+
return ResponseHelper.error("Invalid action: #{action}") unless VALID_ACTIONS.include?(action)
|
|
52
|
+
|
|
53
|
+
hooks_config = RosettAi.root.join('.overcommit.yml')
|
|
54
|
+
return ResponseHelper.error('No .overcommit.yml found') unless hooks_config.exist?
|
|
55
|
+
|
|
56
|
+
data = YAML.safe_load_file(hooks_config, permitted_classes: [Symbol])
|
|
57
|
+
{
|
|
58
|
+
action: action,
|
|
59
|
+
installed: RosettAi.root.join('.git', 'hooks', 'overcommit-hook').exist?,
|
|
60
|
+
hooks: extract_hooks(data)
|
|
61
|
+
}
|
|
62
|
+
rescue Psych::SyntaxError => e
|
|
63
|
+
ResponseHelper.error("Hooks config parse error: #{e.message}")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
# Extracts hook configuration for all overcommit phases.
|
|
69
|
+
#
|
|
70
|
+
# @param data [Hash] parsed .overcommit.yml content
|
|
71
|
+
# @return [Hash{String => Array<String>}] phase to hook names
|
|
72
|
+
def extract_hooks(data)
|
|
73
|
+
return {} unless data.is_a?(Hash)
|
|
74
|
+
|
|
75
|
+
data.each_with_object({}) do |(phase, hooks), result|
|
|
76
|
+
next unless hooks.is_a?(Hash) && HOOK_PHASES.include?(phase)
|
|
77
|
+
|
|
78
|
+
result[phase] = hooks.keys.reject { |k| k == 'ALL' }
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
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: initialize rosett-ai structure.
|
|
10
|
+
#
|
|
11
|
+
# Sets up global, local, or project directory structure.
|
|
12
|
+
# Write operation — creates directories and files.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class InitTool
|
|
17
|
+
TOOL_NAME = 'rai_init'
|
|
18
|
+
DESCRIPTION = 'Initialize rosett-ai directory structure (global, local, or project)'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => false,
|
|
22
|
+
'destructiveHint' => false,
|
|
23
|
+
'idempotentHint' => true,
|
|
24
|
+
'openWorldHint' => false
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
INPUT_SCHEMA = {
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
global: {
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
description: 'Initialize global ~/.claude/ structure (default: false)'
|
|
33
|
+
},
|
|
34
|
+
local: {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
description: 'Initialize project-local .claude/ structure (default: false)'
|
|
37
|
+
},
|
|
38
|
+
project: {
|
|
39
|
+
type: 'boolean',
|
|
40
|
+
description: 'Initialize .rosett-ai/ project structure (default: false)'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}.freeze
|
|
44
|
+
|
|
45
|
+
# Executes the initialization.
|
|
46
|
+
#
|
|
47
|
+
# @param global [Boolean] set up global structure
|
|
48
|
+
# @param local [Boolean] set up project-local structure
|
|
49
|
+
# @param project [Boolean] set up .rosett-ai/ project structure
|
|
50
|
+
# @return [Hash] initialization results
|
|
51
|
+
def call(global: false, local: false, project: false)
|
|
52
|
+
unless global || local || project
|
|
53
|
+
return ResponseHelper.error('At least one scope required: global, local, or project')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
results = { scopes: [], created: [] }
|
|
57
|
+
init_global(results) if global
|
|
58
|
+
init_local(results) if local
|
|
59
|
+
init_project(results) if project
|
|
60
|
+
ResponseHelper.success('Initialization complete', results)
|
|
61
|
+
rescue StandardError => e
|
|
62
|
+
ResponseHelper.error("Init failed: #{e.message}")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
|
|
67
|
+
def init_global(results)
|
|
68
|
+
initializer = RosettAi::Init::GlobalInitializer.new
|
|
69
|
+
initializer.setup
|
|
70
|
+
results[:scopes] << 'global'
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def init_local(results)
|
|
74
|
+
initializer = RosettAi::Init::LocalInitializer.new
|
|
75
|
+
initializer.setup
|
|
76
|
+
results[:scopes] << 'local'
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def init_project(results)
|
|
80
|
+
initializer = RosettAi::Init::ProjectInitializer.new
|
|
81
|
+
initializer.setup
|
|
82
|
+
results[:scopes] << 'project'
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
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 license status.
|
|
10
|
+
#
|
|
11
|
+
# Returns the current license activation status.
|
|
12
|
+
# Read-only operation.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class LicenseStatusTool
|
|
17
|
+
TOOL_NAME = 'rai_license_status'
|
|
18
|
+
DESCRIPTION = 'Show rai license activation status'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => true,
|
|
22
|
+
'destructiveHint' => false,
|
|
23
|
+
'idempotentHint' => true,
|
|
24
|
+
'openWorldHint' => false
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
# Executes the license status check.
|
|
28
|
+
#
|
|
29
|
+
# @return [Hash] license status information
|
|
30
|
+
def call
|
|
31
|
+
result = RosettAi::Licensing::LicenseValidator.new.validate
|
|
32
|
+
{
|
|
33
|
+
active: result[:valid],
|
|
34
|
+
tier: result[:tier]&.to_s,
|
|
35
|
+
key_present: result[:key_present],
|
|
36
|
+
message: result[:message]
|
|
37
|
+
}
|
|
38
|
+
rescue StandardError => e
|
|
39
|
+
ResponseHelper.error("License check failed: #{e.message}")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
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 project status and information.
|
|
10
|
+
#
|
|
11
|
+
# Returns project lifecycle status, info, or drift detection.
|
|
12
|
+
# Read-only operation.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class ProjectTool
|
|
17
|
+
TOOL_NAME = 'rai_project'
|
|
18
|
+
DESCRIPTION = 'Show rai project status, info, or drift detection'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => true,
|
|
22
|
+
'destructiveHint' => false,
|
|
23
|
+
'idempotentHint' => true,
|
|
24
|
+
'openWorldHint' => false
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
VALID_ACTIONS = ['status', 'info', 'drift'].freeze
|
|
28
|
+
|
|
29
|
+
INPUT_SCHEMA = {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
action: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
enum: ['status', 'info', 'drift'],
|
|
35
|
+
description: 'Project action (default: status)'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}.freeze
|
|
39
|
+
|
|
40
|
+
# Executes the project query.
|
|
41
|
+
#
|
|
42
|
+
# @param action [String] one of 'status', 'info', 'drift'
|
|
43
|
+
# @return [Hash] project information
|
|
44
|
+
def call(action: 'status')
|
|
45
|
+
return ResponseHelper.error("Invalid action: #{action}") unless VALID_ACTIONS.include?(action)
|
|
46
|
+
|
|
47
|
+
case action
|
|
48
|
+
when 'status' then action_status
|
|
49
|
+
when 'info' then action_info
|
|
50
|
+
when 'drift' then action_drift
|
|
51
|
+
end
|
|
52
|
+
rescue StandardError => e
|
|
53
|
+
ResponseHelper.error("Project #{action} failed: #{e.message}")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def action_status
|
|
59
|
+
{
|
|
60
|
+
project_root: RosettAi.root.to_s,
|
|
61
|
+
version: RosettAi::VERSION,
|
|
62
|
+
behaviours: count_files('conf/behaviour'),
|
|
63
|
+
designs: count_files('conf/design'),
|
|
64
|
+
engines: detect_engines
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def action_info
|
|
69
|
+
spec = load_gemspec
|
|
70
|
+
{
|
|
71
|
+
name: spec&.name || 'rosett-ai',
|
|
72
|
+
summary: spec&.summary || 'Unknown',
|
|
73
|
+
version: RosettAi::VERSION,
|
|
74
|
+
license: spec&.license || 'Unknown',
|
|
75
|
+
authors: spec&.authors || [],
|
|
76
|
+
homepage: spec&.homepage || 'Unknown',
|
|
77
|
+
ruby_version: RUBY_VERSION,
|
|
78
|
+
required_ruby: spec&.required_ruby_version&.to_s || 'Unknown',
|
|
79
|
+
project_root: RosettAi.root.to_s
|
|
80
|
+
}
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def action_drift
|
|
84
|
+
compiled_dir = Pathname.new(File.expand_path('~/.claude/rules'))
|
|
85
|
+
{
|
|
86
|
+
compiled_rules_exist: compiled_dir.directory?,
|
|
87
|
+
compiled_count: compiled_dir.directory? ? compiled_dir.glob('*.md').size : 0,
|
|
88
|
+
source_count: count_files('conf/behaviour') + count_files('conf/design')
|
|
89
|
+
}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def count_files(subdir)
|
|
93
|
+
dir = RosettAi.root.join(subdir)
|
|
94
|
+
dir.directory? ? dir.glob('*.yml').size : 0
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def detect_engines
|
|
98
|
+
RosettAi::Plugins::Registry.available(:engine).size
|
|
99
|
+
rescue StandardError
|
|
100
|
+
0
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Loads the gemspec from the project root.
|
|
104
|
+
#
|
|
105
|
+
# @return [Gem::Specification, nil]
|
|
106
|
+
def load_gemspec
|
|
107
|
+
gemspec = RosettAi.root.glob('*.gemspec').first
|
|
108
|
+
return nil unless gemspec&.exist?
|
|
109
|
+
|
|
110
|
+
Gem::Specification.load(gemspec.to_s)
|
|
111
|
+
rescue StandardError
|
|
112
|
+
nil
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
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: query AI provenance information.
|
|
10
|
+
#
|
|
11
|
+
# Validates, shows, and logs provenance entries.
|
|
12
|
+
# Read-only operation.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class ProvenanceTool
|
|
17
|
+
TOOL_NAME = 'rai_provenance'
|
|
18
|
+
DESCRIPTION = 'Query AI provenance (validate, show, log)'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => true,
|
|
22
|
+
'destructiveHint' => false,
|
|
23
|
+
'idempotentHint' => true,
|
|
24
|
+
'openWorldHint' => false
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
VALID_ACTIONS = ['validate', 'show', 'log'].freeze
|
|
28
|
+
|
|
29
|
+
INPUT_SCHEMA = {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
action: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
enum: ['validate', 'show', 'log'],
|
|
35
|
+
description: 'Provenance action (default: log)'
|
|
36
|
+
},
|
|
37
|
+
commit: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
description: 'Commit SHA to show provenance for (for show action)'
|
|
40
|
+
},
|
|
41
|
+
file: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
description: 'File path to show provenance for (for show action)'
|
|
44
|
+
},
|
|
45
|
+
role: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
description: 'Filter by AI role (for log action)'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}.freeze
|
|
51
|
+
|
|
52
|
+
# Executes the provenance query.
|
|
53
|
+
#
|
|
54
|
+
# @param action [String] one of 'validate', 'show', 'log'
|
|
55
|
+
# @param commit [String, nil] commit SHA for show action
|
|
56
|
+
# @param file [String, nil] file path filter
|
|
57
|
+
# @param role [String, nil] AI role filter for log
|
|
58
|
+
# @return [Hash] provenance information
|
|
59
|
+
def call(action: 'log', commit: nil, file: nil, role: nil)
|
|
60
|
+
return ResponseHelper.error("Invalid action: #{action}") unless VALID_ACTIONS.include?(action)
|
|
61
|
+
|
|
62
|
+
tracker = RosettAi::Provenance::Tracker.new
|
|
63
|
+
case action
|
|
64
|
+
when 'validate' then action_validate(tracker)
|
|
65
|
+
when 'show' then action_show(tracker, commit: commit, file: file)
|
|
66
|
+
when 'log' then action_log(tracker, role: role)
|
|
67
|
+
end
|
|
68
|
+
rescue StandardError => e
|
|
69
|
+
ResponseHelper.error("Provenance #{action} failed: #{e.message}")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def action_validate(tracker)
|
|
75
|
+
results = tracker.validate
|
|
76
|
+
{ valid: results[:errors].empty?, errors: results[:errors] }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def action_show(tracker, commit:, file:)
|
|
80
|
+
entries = if commit
|
|
81
|
+
[tracker.find_by_commit(commit)].compact
|
|
82
|
+
elsif file
|
|
83
|
+
tracker.find_by_file(file)
|
|
84
|
+
else
|
|
85
|
+
return ResponseHelper.error('Either commit or file is required for show')
|
|
86
|
+
end
|
|
87
|
+
{ entries: entries }
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def action_log(tracker, role:)
|
|
91
|
+
entries = tracker.log(role: role)
|
|
92
|
+
{ entries: entries, total: entries.size }
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
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
|
+
module Mcp
|
|
8
|
+
module Tools
|
|
9
|
+
# MCP tool: initialize provenance tracking.
|
|
10
|
+
#
|
|
11
|
+
# Creates .ai-provenance.yml in the project root.
|
|
12
|
+
# Write operation — creates a new file.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class ProvenanceWriteTool
|
|
17
|
+
TOOL_NAME = 'rai_provenance_init'
|
|
18
|
+
DESCRIPTION = 'Initialize AI provenance tracking in a project'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => false,
|
|
22
|
+
'destructiveHint' => false,
|
|
23
|
+
'idempotentHint' => true,
|
|
24
|
+
'openWorldHint' => false
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
# Executes the provenance initialization.
|
|
28
|
+
#
|
|
29
|
+
# @return [Hash] initialization result
|
|
30
|
+
def call
|
|
31
|
+
store = RosettAi::Provenance::Store.new(root: Dir.pwd)
|
|
32
|
+
store.init
|
|
33
|
+
ResponseHelper.success('Provenance tracking initialized', path: store.path.to_s)
|
|
34
|
+
rescue StandardError => e
|
|
35
|
+
ResponseHelper.error("Provenance init failed: #{e.message}")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|