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,122 @@
|
|
|
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 'digest'
|
|
7
|
+
require 'pathname'
|
|
8
|
+
|
|
9
|
+
module RosettAi
|
|
10
|
+
module Mcp
|
|
11
|
+
module Tools
|
|
12
|
+
# MCP tool: show compilation staleness status.
|
|
13
|
+
#
|
|
14
|
+
# Compares source behaviour/design YAML files against their compiled
|
|
15
|
+
# output, reporting per-file checksums and staleness. Read-only.
|
|
16
|
+
#
|
|
17
|
+
# @author hugo
|
|
18
|
+
# @author claude
|
|
19
|
+
class CompileStatusTool
|
|
20
|
+
TOOL_NAME = 'rai_compile_status'
|
|
21
|
+
DESCRIPTION = 'Show compiled rules staleness — source vs compiled checksums'
|
|
22
|
+
|
|
23
|
+
ANNOTATIONS = {
|
|
24
|
+
'readOnlyHint' => true,
|
|
25
|
+
'destructiveHint' => false,
|
|
26
|
+
'idempotentHint' => true,
|
|
27
|
+
'openWorldHint' => false
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
30
|
+
INPUT_SCHEMA = {
|
|
31
|
+
type: 'object',
|
|
32
|
+
properties: {
|
|
33
|
+
scope: {
|
|
34
|
+
type: 'string',
|
|
35
|
+
description: 'Scope to check staleness for (default: all)'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}.freeze
|
|
39
|
+
|
|
40
|
+
# Checks staleness of compiled output files.
|
|
41
|
+
#
|
|
42
|
+
# @param scope [String, nil] optional filter ('behaviour', 'design')
|
|
43
|
+
# @return [Hash] per-file staleness report
|
|
44
|
+
def call(scope: nil)
|
|
45
|
+
compiled_dir = RosettAi.paths.rules_dir
|
|
46
|
+
source_dir = resolve_source_dir
|
|
47
|
+
|
|
48
|
+
files = collect_source_files(source_dir, scope)
|
|
49
|
+
report = files.map { |src| build_file_report(src, compiled_dir) }
|
|
50
|
+
|
|
51
|
+
stale_count = report.count { |r| r[:stale] }
|
|
52
|
+
{
|
|
53
|
+
files: report,
|
|
54
|
+
total: report.size,
|
|
55
|
+
stale: stale_count,
|
|
56
|
+
up_to_date: report.size - stale_count,
|
|
57
|
+
compiled_dir: compiled_dir.to_s,
|
|
58
|
+
source_dir: source_dir.to_s
|
|
59
|
+
}
|
|
60
|
+
rescue StandardError => e
|
|
61
|
+
ResponseHelper.error("Compile status failed: #{e.message}")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
# @return [Pathname]
|
|
67
|
+
def resolve_source_dir
|
|
68
|
+
return RosettAi.root.join('conf') if RosettAi.context.rai_internal?
|
|
69
|
+
|
|
70
|
+
RosettAi.paths.rai_conf_dir
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @param source_dir [Pathname]
|
|
74
|
+
# @param scope [String, nil]
|
|
75
|
+
# @return [Array<Pathname>]
|
|
76
|
+
def collect_source_files(source_dir, scope)
|
|
77
|
+
categories = scope ? [scope] : ['behaviour', 'design']
|
|
78
|
+
categories.flat_map do |cat|
|
|
79
|
+
dir = source_dir.join(cat)
|
|
80
|
+
dir.directory? ? dir.glob('*.yml').sort : []
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# @param source_path [Pathname]
|
|
85
|
+
# @param compiled_dir [Pathname]
|
|
86
|
+
# @return [Hash]
|
|
87
|
+
def build_file_report(source_path, compiled_dir)
|
|
88
|
+
category = source_path.parent.basename.to_s
|
|
89
|
+
basename = source_path.basename('.yml').to_s
|
|
90
|
+
compiled_name = "#{category}-#{basename}.md"
|
|
91
|
+
compiled_path = compiled_dir.join(compiled_name)
|
|
92
|
+
|
|
93
|
+
source_checksum = file_checksum(source_path)
|
|
94
|
+
compiled_exists = compiled_path.exist?
|
|
95
|
+
compiled_checksum = compiled_exists ? file_checksum(compiled_path) : nil
|
|
96
|
+
|
|
97
|
+
{
|
|
98
|
+
source: source_path.to_s,
|
|
99
|
+
compiled: compiled_path.to_s,
|
|
100
|
+
source_checksum: source_checksum,
|
|
101
|
+
compiled_checksum: compiled_checksum,
|
|
102
|
+
compiled_exists: compiled_exists,
|
|
103
|
+
stale: !compiled_exists || source_newer?(source_path, compiled_path)
|
|
104
|
+
}
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @param path [Pathname]
|
|
108
|
+
# @return [String] SHA-256 hex digest
|
|
109
|
+
def file_checksum(path)
|
|
110
|
+
Digest::SHA256.hexdigest(path.read)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# @param source [Pathname]
|
|
114
|
+
# @param compiled [Pathname]
|
|
115
|
+
# @return [Boolean]
|
|
116
|
+
def source_newer?(source, compiled)
|
|
117
|
+
source.mtime > compiled.mtime
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,191 @@
|
|
|
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 'fileutils'
|
|
7
|
+
require 'digest'
|
|
8
|
+
|
|
9
|
+
module RosettAi
|
|
10
|
+
module Mcp
|
|
11
|
+
module Tools
|
|
12
|
+
# MCP tool: compile rai behaviours to engine-native format.
|
|
13
|
+
#
|
|
14
|
+
# Delegates to the real {RosettAi::Compiler::CompilationPipeline}.
|
|
15
|
+
# When simulate=true, returns diffs without writing files.
|
|
16
|
+
# When simulate=false, writes compiled output to disk.
|
|
17
|
+
#
|
|
18
|
+
# @author hugo
|
|
19
|
+
# @author claude
|
|
20
|
+
class CompileTool
|
|
21
|
+
TOOL_NAME = 'rai_compile'
|
|
22
|
+
DESCRIPTION = 'Compile rai behaviours to engine-native format'
|
|
23
|
+
|
|
24
|
+
ANNOTATIONS = {
|
|
25
|
+
'readOnlyHint' => false,
|
|
26
|
+
'destructiveHint' => false,
|
|
27
|
+
'idempotentHint' => true,
|
|
28
|
+
'openWorldHint' => false
|
|
29
|
+
}.freeze
|
|
30
|
+
|
|
31
|
+
INPUT_SCHEMA = {
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
simulate: {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
description: 'Dry-run mode — show what would change without writing (default: true)'
|
|
37
|
+
},
|
|
38
|
+
engine: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: 'Target engine format (default: claude)'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}.freeze
|
|
44
|
+
|
|
45
|
+
# Executes the compilation via the real pipeline.
|
|
46
|
+
#
|
|
47
|
+
# @param simulate [Boolean] dry-run mode (default true)
|
|
48
|
+
# @param engine [String] target engine (default 'claude')
|
|
49
|
+
# @return [Hash] result with compiled file details
|
|
50
|
+
def call(simulate: true, engine: 'claude')
|
|
51
|
+
backend = RosettAi::Compiler::Backend.for(engine)
|
|
52
|
+
pipeline = build_pipeline(backend)
|
|
53
|
+
compiled = pipeline.compile
|
|
54
|
+
|
|
55
|
+
if simulate
|
|
56
|
+
build_simulate_result(pipeline, compiled, engine)
|
|
57
|
+
else
|
|
58
|
+
build_write_result(pipeline, compiled, engine)
|
|
59
|
+
end
|
|
60
|
+
rescue RosettAi::Error => e
|
|
61
|
+
ResponseHelper.error("Compilation failed: #{e.message}")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
# @param backend [RosettAi::Compiler::Backend] rendering backend
|
|
67
|
+
# @return [RosettAi::Compiler::CompilationPipeline]
|
|
68
|
+
def build_pipeline(backend)
|
|
69
|
+
scope = detect_scope
|
|
70
|
+
RosettAi::Compiler::CompilationPipeline.new(
|
|
71
|
+
source_dir: resolve_source_dir(scope),
|
|
72
|
+
target_dir: resolve_target_dir(backend, scope),
|
|
73
|
+
schema_dir: RosettAi.root.join('conf', 'schemas'),
|
|
74
|
+
backend: backend,
|
|
75
|
+
scope: scope,
|
|
76
|
+
additional_source_dirs: additional_dirs(scope)
|
|
77
|
+
)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# @return [Symbol] :global or :project
|
|
81
|
+
def detect_scope
|
|
82
|
+
ctx = RosettAi.context
|
|
83
|
+
ctx.project? && !ctx.rai_internal? ? :project : :global
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @param scope [Symbol]
|
|
87
|
+
# @return [Pathname]
|
|
88
|
+
def resolve_source_dir(scope)
|
|
89
|
+
return RosettAi.root.join('conf') if RosettAi.context.rai_internal?
|
|
90
|
+
|
|
91
|
+
scope == :project ? RosettAi.conf_root.join('conf') : RosettAi.paths.rai_conf_dir
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# @param backend [RosettAi::Compiler::Backend]
|
|
95
|
+
# @param scope [Symbol]
|
|
96
|
+
# @return [Pathname]
|
|
97
|
+
def resolve_target_dir(backend, scope)
|
|
98
|
+
dir = backend.profile.output_dir
|
|
99
|
+
return Pathname.new(File.expand_path(dir)) if dir
|
|
100
|
+
|
|
101
|
+
return RosettAi.context.project_root.join('.claude', 'rules') if scope == :project
|
|
102
|
+
|
|
103
|
+
RosettAi.paths.rules_dir
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# @param scope [Symbol]
|
|
107
|
+
# @return [Array<Pathname>]
|
|
108
|
+
def additional_dirs(scope)
|
|
109
|
+
dirs = []
|
|
110
|
+
packaged = RosettAi.paths.packaged_conf_dir
|
|
111
|
+
dirs << packaged if packaged.directory?
|
|
112
|
+
dirs << RosettAi.paths.rai_conf_dir if scope == :project || RosettAi.context.rai_internal?
|
|
113
|
+
dirs
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @param pipeline [RosettAi::Compiler::CompilationPipeline]
|
|
117
|
+
# @param compiled [Hash]
|
|
118
|
+
# @param engine [String]
|
|
119
|
+
# @return [Hash]
|
|
120
|
+
def build_simulate_result(pipeline, compiled, engine)
|
|
121
|
+
files = compiled.map do |filename, info|
|
|
122
|
+
target = pipeline.target_dir.join(filename)
|
|
123
|
+
existing = File.exist?(target)
|
|
124
|
+
{
|
|
125
|
+
filename: filename,
|
|
126
|
+
exists: existing,
|
|
127
|
+
stale: existing ? !pipeline.diff(target, info[:content]).nil? : true
|
|
128
|
+
}
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
{
|
|
132
|
+
simulate: true,
|
|
133
|
+
engine: engine,
|
|
134
|
+
status: 'dry-run',
|
|
135
|
+
files: files,
|
|
136
|
+
total: compiled.size,
|
|
137
|
+
message: "Simulation complete — #{compiled.size} file(s), no files written"
|
|
138
|
+
}
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# @param pipeline [RosettAi::Compiler::CompilationPipeline]
|
|
142
|
+
# @param compiled [Hash]
|
|
143
|
+
# @param engine [String]
|
|
144
|
+
# @return [Hash]
|
|
145
|
+
def build_write_result(pipeline, compiled, engine)
|
|
146
|
+
results = { created: [], updated: [], unchanged: [] }
|
|
147
|
+
|
|
148
|
+
compiled.each do |filename, info|
|
|
149
|
+
target = pipeline.target_dir.join(filename)
|
|
150
|
+
FileUtils.mkdir_p(target.dirname)
|
|
151
|
+
action = write_compiled_file(pipeline, target, info[:content])
|
|
152
|
+
results[action] << filename
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
{
|
|
156
|
+
simulate: false,
|
|
157
|
+
engine: engine,
|
|
158
|
+
status: 'compiled',
|
|
159
|
+
created: results[:created],
|
|
160
|
+
updated: results[:updated],
|
|
161
|
+
unchanged: results[:unchanged],
|
|
162
|
+
total: compiled.size,
|
|
163
|
+
message: "Compilation complete — #{results[:created].size} created, " \
|
|
164
|
+
"#{results[:updated].size} updated, #{results[:unchanged].size} unchanged"
|
|
165
|
+
}
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# @param pipeline [RosettAi::Compiler::CompilationPipeline]
|
|
169
|
+
# @param target [Pathname]
|
|
170
|
+
# @param content [String]
|
|
171
|
+
# @return [Symbol] :created, :updated, or :unchanged
|
|
172
|
+
def write_compiled_file(pipeline, target, content)
|
|
173
|
+
unless File.exist?(target)
|
|
174
|
+
File.write(target, content)
|
|
175
|
+
return :created
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
existing_checksum = pipeline.checksum(File.read(target, encoding: 'utf-8'))
|
|
179
|
+
new_checksum = pipeline.checksum(content)
|
|
180
|
+
|
|
181
|
+
if existing_checksum == new_checksum
|
|
182
|
+
:unchanged
|
|
183
|
+
else
|
|
184
|
+
File.write(target, content)
|
|
185
|
+
:updated
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
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 rosett-ai compliance checks.
|
|
10
|
+
#
|
|
11
|
+
# Executes CRA, license, and SPDX header checks.
|
|
12
|
+
# Read-only operation — does not modify any files.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class ComplyTool
|
|
17
|
+
TOOL_NAME = 'rai_comply'
|
|
18
|
+
DESCRIPTION = 'Run rosett-ai compliance checks (CRA, license, SPDX headers)'
|
|
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
|
+
cra: {
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
description: 'Run CRA-specific checks only (default: false)'
|
|
33
|
+
},
|
|
34
|
+
license: {
|
|
35
|
+
type: 'boolean',
|
|
36
|
+
description: 'Run license audit checks only (default: false)'
|
|
37
|
+
},
|
|
38
|
+
headers: {
|
|
39
|
+
type: 'boolean',
|
|
40
|
+
description: 'Run SPDX header checks only (default: false)'
|
|
41
|
+
},
|
|
42
|
+
format: {
|
|
43
|
+
type: 'string',
|
|
44
|
+
enum: ['json', 'text'],
|
|
45
|
+
description: 'Output format (default: json)'
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}.freeze
|
|
49
|
+
|
|
50
|
+
# Executes compliance checks.
|
|
51
|
+
#
|
|
52
|
+
# @param cra [Boolean] run CRA checks only
|
|
53
|
+
# @param license [Boolean] run license checks only
|
|
54
|
+
# @param headers [Boolean] run SPDX header checks only
|
|
55
|
+
# @param format [String] output format ('json' or 'text')
|
|
56
|
+
# @return [Hash] compliance results
|
|
57
|
+
def call(cra: false, license: false, headers: false, format: 'json')
|
|
58
|
+
checks = filter_checks(cra: cra, license: license, headers: headers)
|
|
59
|
+
results = run_checks(checks)
|
|
60
|
+
violations = results.select { |r| r[:status] == 'fail' }
|
|
61
|
+
{ compliant: violations.empty?, results: results, violations: violations, format: format }
|
|
62
|
+
rescue StandardError => e
|
|
63
|
+
ResponseHelper.error("Compliance check failed: #{e.message}")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def filter_checks(cra:, license:, headers:)
|
|
69
|
+
selected = { cra: cra, license: license, headers: headers }.select { |_, v| v }.keys
|
|
70
|
+
selected.empty? ? nil : selected
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def run_checks(checks)
|
|
74
|
+
RosettAi::Comply::Runner.new(project_root: RosettAi.root, checks: checks).run
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
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: compile Claude Code configuration.
|
|
10
|
+
#
|
|
11
|
+
# Compiles YAML scopes to JSON settings files.
|
|
12
|
+
# Requires an engine plugin with config compiler support.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class ConfigCompileTool
|
|
17
|
+
TOOL_NAME = 'rai_config_compile'
|
|
18
|
+
DESCRIPTION = 'Compile rai configuration scopes to JSON settings'
|
|
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
|
+
simulate: {
|
|
31
|
+
type: 'boolean',
|
|
32
|
+
description: 'Dry-run mode (default: true)'
|
|
33
|
+
},
|
|
34
|
+
scope: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
description: 'Compile a specific scope only (e.g. managed, user, project)'
|
|
37
|
+
},
|
|
38
|
+
engine: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description: 'Target engine (default: claude)'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}.freeze
|
|
44
|
+
|
|
45
|
+
# Executes the configuration compilation.
|
|
46
|
+
#
|
|
47
|
+
# @param simulate [Boolean] dry-run mode
|
|
48
|
+
# @param scope [String, nil] specific scope to compile
|
|
49
|
+
# @param engine [String] target engine
|
|
50
|
+
# @return [Hash] compilation results
|
|
51
|
+
def call(simulate: true, scope: nil, engine: 'claude')
|
|
52
|
+
plugin = RosettAi::Plugins::Registry.plugin_module(:engine, engine)
|
|
53
|
+
compiler_class = plugin&.config_compiler_class
|
|
54
|
+
unless compiler_class
|
|
55
|
+
return ResponseHelper.error(
|
|
56
|
+
"Engine '#{engine}' has no config compiler. " \
|
|
57
|
+
'Install an engine plugin to enable config compilation.'
|
|
58
|
+
)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
results = compiler_class.new(simulate: simulate).compile_all(scope: scope)
|
|
62
|
+
{ simulate: simulate, scope: scope, engine: engine,
|
|
63
|
+
status: simulate ? 'dry-run' : 'compiled',
|
|
64
|
+
files: results[:files], message: results[:message] }
|
|
65
|
+
rescue StandardError => e
|
|
66
|
+
ResponseHelper.error("Config compile failed: #{e.message}")
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
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 rai configuration status.
|
|
10
|
+
#
|
|
11
|
+
# Returns the current state of rai configuration including
|
|
12
|
+
# project info, engine status, and validation state.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class ConfigStatusTool
|
|
17
|
+
TOOL_NAME = 'rai_config_status'
|
|
18
|
+
DESCRIPTION = 'Show rai configuration and project status'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => true,
|
|
22
|
+
'destructiveHint' => false,
|
|
23
|
+
'idempotentHint' => true,
|
|
24
|
+
'openWorldHint' => false
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
# Executes the status check.
|
|
28
|
+
#
|
|
29
|
+
# @return [Hash] result with configuration status
|
|
30
|
+
def call
|
|
31
|
+
{
|
|
32
|
+
version: RosettAi::VERSION,
|
|
33
|
+
project_root: RosettAi.root.to_s,
|
|
34
|
+
behaviours: count_files('conf/behaviour'),
|
|
35
|
+
designs: count_files('conf/design'),
|
|
36
|
+
engines: detect_engines,
|
|
37
|
+
default_engine: detect_default_engine,
|
|
38
|
+
scope: detect_scope
|
|
39
|
+
}
|
|
40
|
+
rescue StandardError => e
|
|
41
|
+
ResponseHelper.error("Config status failed: #{e.message}")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
# @param subdir [String]
|
|
47
|
+
# @return [Integer]
|
|
48
|
+
def count_files(subdir)
|
|
49
|
+
dir = RosettAi.root.join(subdir)
|
|
50
|
+
dir.directory? ? dir.glob('*.yml').size : 0
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @return [Hash] engine count and any error
|
|
54
|
+
def detect_engines
|
|
55
|
+
registry = RosettAi::Plugins::Registry
|
|
56
|
+
count = registry.respond_to?(:discovered) ? registry.discovered.size : 0
|
|
57
|
+
{ count: count }
|
|
58
|
+
rescue StandardError => e
|
|
59
|
+
{ count: 0, error: e.message }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# @return [String] default engine name or error detail
|
|
63
|
+
def detect_default_engine
|
|
64
|
+
RosettAi.rai_config.default_engine
|
|
65
|
+
rescue StandardError => e
|
|
66
|
+
"unknown (#{e.message})"
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @return [String] detected compilation scope
|
|
70
|
+
def detect_scope
|
|
71
|
+
ctx = RosettAi.context
|
|
72
|
+
ctx.project? && !ctx.rai_internal? ? 'project' : 'global'
|
|
73
|
+
rescue StandardError
|
|
74
|
+
'unknown'
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
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 content packs.
|
|
10
|
+
#
|
|
11
|
+
# List, install, or update content packs.
|
|
12
|
+
# Write operation for install/update actions.
|
|
13
|
+
#
|
|
14
|
+
# @author hugo
|
|
15
|
+
# @author claude
|
|
16
|
+
class ContentTool
|
|
17
|
+
TOOL_NAME = 'rai_content'
|
|
18
|
+
DESCRIPTION = 'List, install, or update rai content packs'
|
|
19
|
+
|
|
20
|
+
ANNOTATIONS = {
|
|
21
|
+
'readOnlyHint' => false,
|
|
22
|
+
'destructiveHint' => false,
|
|
23
|
+
'idempotentHint' => true,
|
|
24
|
+
'openWorldHint' => true
|
|
25
|
+
}.freeze
|
|
26
|
+
|
|
27
|
+
VALID_ACTIONS = ['list', 'install', 'update'].freeze
|
|
28
|
+
|
|
29
|
+
INPUT_SCHEMA = {
|
|
30
|
+
type: 'object',
|
|
31
|
+
properties: {
|
|
32
|
+
action: {
|
|
33
|
+
type: 'string',
|
|
34
|
+
enum: ['list', 'install', 'update'],
|
|
35
|
+
description: 'Content action (default: list)'
|
|
36
|
+
},
|
|
37
|
+
pack_name: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
description: 'Content pack name (required for install)'
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}.freeze
|
|
43
|
+
|
|
44
|
+
# Executes the content pack operation.
|
|
45
|
+
#
|
|
46
|
+
# @param action [String] one of 'list', 'install', 'update'
|
|
47
|
+
# @param pack_name [String, nil] pack name for install
|
|
48
|
+
# @return [Hash] operation result
|
|
49
|
+
def call(action: 'list', pack_name: nil)
|
|
50
|
+
return ResponseHelper.error("Invalid action: #{action}") unless VALID_ACTIONS.include?(action)
|
|
51
|
+
|
|
52
|
+
case action
|
|
53
|
+
when 'list' then action_list
|
|
54
|
+
when 'install' then action_install(pack_name)
|
|
55
|
+
when 'update' then ResponseHelper.error('Content update requires CLI: raictl content update')
|
|
56
|
+
end
|
|
57
|
+
rescue StandardError => e
|
|
58
|
+
ResponseHelper.error("Content #{action} failed: #{e.message}")
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def action_list
|
|
64
|
+
registry = RosettAi::Content::PackRegistry.new
|
|
65
|
+
{ packs: registry.installed }
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def action_install(pack_name)
|
|
69
|
+
return ResponseHelper.error('Pack name required for install') unless pack_name
|
|
70
|
+
|
|
71
|
+
ResponseHelper.error(
|
|
72
|
+
"Content install requires CLI with license key: raictl content install #{pack_name}"
|
|
73
|
+
)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|